linux shell 编程小记

if 条件 OPTION

OPTION 解释
[-a file] 如果file存在则为真 ,也可以表示为 and: 条件与
if [ -z “condition1” -a -z “condition2” ]
[-b file] 如果file存在且是一个特殊文件则为真
[-c file] 如果file存在且是一个特殊文件则为真
[-d file] 如果 file 文件存在且是一个目录则为真,d前的!是逻辑非 
#表示目录不存在,则执行后面的 then 操作 
if [ ! -d lcd_path/par_date ]
[-e file] 如果 file文件存在则为真
[-f file] 如果 file 存在且是一个普通文件则为真
[-g file] 如果 file 存在且已经设置了SGID则为真(SUID 是 Set User ID, SGID 是 Set Group ID的意思)
[-h file] 如果 file 存在且是一个符号连接则为真
[-k file] 如果 file 存在且已经设置粘制位则为真
[-p file] 如果file存在且是一个名字管道(F如果O)则为真。管道是linux里面进程间通信的一种方式,
其他的还有像信号(signal)、信号量、消息队列、共享内存、套接字(socket)等
[-r file] 如果file存在且是可读的则为真
[-s file] 如果file存在且大小不为0则为真
[-t FD] 如果文件描述符FD打开且指向一个终端则为真
[-u file] 如果file存在且设置了SUID(set userID)则为真
[-w file 如果file存在且是可写的则为真
[-x file] 如果file存在且是可执行的则为真
[-O file] 如果file存在且属有效用户ID则为真
[-G file] 如果file存在且属有效用户组则为真
[-L file] 如果file存在且是一个符号连接则为真
[-N file] 如果file存在and has been mod如果ied since it was last read则为真
[-S file] 如果file存在且是一个套接字则为真
[-o optionname] 如果shell选项“optionname”开启则为真
[-z string] “string”的长度为零则为真
[-n string] or [string] “string”的长度为非零non-zero则为真

if 基本判断

  • [file1 –nt file2] 如果file1 has been changed more recently than file2或者file1 exists and file2 does not则为真 
  • [file1 –ot file2] 如果file1比file2要老,或者file2存在且file1不存在则为真 
  • [file1 –ef file2] 如果file1和file2指向相同的设备和节点号则为真 
  • [sting1==string2] 如果2个字符串相同。“=”may be used instead of “==”for strict posix compliance则为真 
  • [string1!=string2] 如果字符串不相等则为真 
  • [string1<string2] 如果“string1”sorts before“string2”lexicographically in the current locale则为真 
  • [arg1 OP arg2]  “OP”is one of –eq,-ne,-lt,-le,-gt or –ge

截取字符串

  • # 号截取,删除左边字符,保留右边字符。 (非贪婪匹配)
1
2
3
4
var=http://www.glmapper.com
# # 号是运算符,*/ 表示从左边开始删除第一个 / 号及左边的所有字符,即删除 http://
echo ${var#*//}
#结果 www.glmapper.com
  • ## 号截取,删除左边字符,保留右边字符。(贪婪匹配)****
1
2
3
4
5
var=http://www.glmapper.com
# ##*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符
echo ${var##*//}

# 结果 www.glmapper.com
  • %号截取,删除右边字符,保留左边字符 (非贪婪匹配)
1
2
3
4
var=http://www.glmapper.com
# %/* 表示从右边开始,删除第一个 / 号及右边的字符
echo ${var%/*}
# 结果是:http:/
  • %% 号截取,删除右边字符,保留左边字符  (贪婪匹配)
1
2
3
4
var=http://www.glmapper.com
# %%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符
echo ${var%%/*}
# 结果 :http:
  • 从左边第几个字符开始,及字符的个数
1
2
3
4
var=http://www.glmapper.com
# 其中的 0 表示左边第一个字符开始,5 表示字符的总个数
echo ${var:0:5}
# 结果 http:
  • 从左边第几个字符开始,一直到结束
1
2
3
4
var=http://www.glmapper.com
# 其中的 7 表示左边第8个字符开始,一直到结束。
echo ${var:7}
# 结果 www.glmapper.com
  • 从右边第几个字符开始,及字符的个数
1
2
3
4
var=http://www.glmapper.com
# 其中的 0-3 表示右边算起第3个字符开始,3 表示字符的个数
echo ${var:0-3:3}
# 结果 com
  • 从右边第几个字符开始,一直到结束
1
2
3
4
var=http://www.glmapper.com
# 表示从右边第 3 个字符开始,一直到结束
echo ${var:0-3}
# 结果 com

左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示

basename

basename 命令简介

去除文件名的目录部分和后缀部分。basename 命令读取 String 参数,删除以 /(斜杠) 结尾的前缀以及任何指定的 Suffix 参数,并将剩余的基本文件名称写至标准输出。basename 和 dirname 命令通常用于 shell 脚本中的命令替换来指定和指定的输入文件名称有所差异的输出文件名称。
**
基本语法如下:

1
2
basename NAME [SUFFIX]
basename OPTION

基本示例

1
2
3
4
5
basename /usr/bin/sort
# 返回 sort

basename /usr/bin/sort/glmapper.txt
# 返回 glmapper.txt

创建基本文件名称的规则

  • 如果 String 参数是 //(双斜杠) 或如果 String 参数包含的都是斜杠字符,则将字符串更改为单个 /(斜杠)
1
2
3
4
5
basename //usr//bin//sort//glmapper.txt
# 返回 glmapper.txt

basename ////
# 返回 /
  • 从指定字符串除去任何拖尾的 / 字符。
1
2
basename /usr/bin/sort/
# 返回 sort
  • 如果在 String 参数中剩余任何 / 字符,则除去字符串的前缀直到(包含)最后一个 / 字符。
  • 如果指定 Suffix 参数,且它和字符串中的剩余的字符相同,则不修改此字符串
1
2
3
4
5
basename /usr/bin/sort/glmapper.txt glmapper.txt 
# 返回glmapper.txt

basename /usr/bin/sort/glmapper.txt .txt
# 返回 glmapper

shell 查看当前目录下文件的个数

测试准备,test 目录下有 test1、test2 两个文件夹和一个 1.txt 文件。

1
2
3
4
5
-test
├── 1.txt
├── test1
│   └── test1_1.txt
└── test2
  • 查看当前目录下文件的个数
1
2
test ls -l | grep "^-" | wc -l
1 # 1.txt
  • 查看当前目录下文件的个数,包括子目录里的
1
2
test ls -lR| grep "^-" | wc -l
2 # 1.txt test1_1.txt
  • 查看某目录下文件夹(目录)的个数,包括子目录里的
1
2
test ls -lR| grep "^d" | wc -l
2 # test1 test2
  • 说明:
1
2
3
4
1、ls -l :长列表输出该目录下文件信息(注意这里的文件,不同于一般的文件,可能是目录、链接、设备文件等)
2、grep "^-" :这里将长列表输出信息过滤一部分,只保留一般文件,如果只保留目录就是 ^d
3、wc -l : 统计输出信息的行数,已经过滤得只剩一般文件了,统计结果就是一般文件信息的行数,
又一行信息对应一个文件,也就是文件的个数

利用简单的命令组合实现配置文件的获取

测试准备,在 1.txt 中 增加两个属性:

1
2
name=glmapper
age=26
1
2
3
4
5
cat /Users/guolei/logs/test/1.txt | sed 's|[[:blank:]]||g' | grep "^name=" | cut -d= -f2
# 返回 glmapper

cat /Users/guolei/logs/test/1.txt | sed 's|[[:blank:]]||g' | grep "^age=" | cut -d= -f2
# 返回 26

函数封装与返回

以上面的解析配置文件为例,将其封装成一个函数

1
2
3
4
5
6
7
8
function load_param()
{
# 接受的第一个参数是文件地址
local properties_file=$1
# 接受的第二个参数是属性名
local param=$2
RESULT=`cat $properties_file | sed 's|[[:blank:]]||g' | grep "^$param=" | cut -d= -f2`
}

调用函数并且获取返回值

1
2
3
4
load_param 1.txt name
PROP_VAL=$RESULT
echo $PROP_VAL
# 返回 glmapper

shell 实现日志文件的归档处理

日志归档简单来说就是,每次希望启动,会将前一次程序运行产生的日志和本地运行产生的日志隔离开来,归档结果就是产生类似于如下的日志文件:

  • stdout.log.20170909
  • stdout.log.20170709
  • stdout

所以日志文件的归档在生产脚本中是必须要考虑的,否则就到导致每次产生的文件都会被写入同一份日志文件中。下面是实践过程中归纳的一个日志归档函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# archive log
function archive_log() {
local FILE_STDOUT_LOG=$LOG_ROOT/stdout.log
local FILE_STDERR_LOG=$LOG_ROOT/stderr.log
if [ ! -e $LOG_ROOT ] ; then
mkdir -p $LOG_ROOT
fi
NOW=`date +%Y%m%d.%H%M%S`
# scroll SOFABoot STDOUT log
if [ -e $FILE_STDOUT_LOG ] ; then
mv $FILE_STDOUT_LOG $FILE_STDOUT_LOG.$NOW
fi

# scroll SOFABoot STDERR log
if [ -e $FILE_STDERR_LOG ] ; then
mv $FILE_STDERR_LOG $FILE_STDERR_LOG.$NOW
fi

FILE_STDOUT_LOG_GLOBAL=$FILE_STDOUT_LOG;
FILE_STDERR_LOG_GLOBAL=$FILE_STDERR_LOG;
}

一个简单的 SOFABoot 启动脚本

deploy.sh  简单的启动脚本:

1
2
3
4
5
6
7
8
9
10
11
12
LOG_ROOT= $1;
APP_PATH= $2;
# 检查 JAVA_HOME
if [ -z "$JAVA_HOME" ]; then
echo "JAVA_HOME not set, exit"
exit 1
fi
# 使用前面的那个日志归档函数
archive_log

# 启动 java 程序
java -jar $APP_PATH >> $FILE_STDOUT_LOG_GLOBAL 2>> $FILE_STDOUT_LOG_GLOBAL &

运行:

1
sh deploy.sh ./logs app.jar 

小结

本文记录日常中常遇到的 shell 命令,基础知识部分零碎的参考了网上一些同学的博客,在此做了归纳。也欢迎大家指正。如果你有比较骚气的操作,也欢迎评论席留言,我会验证后更新到文章中来。

作者

卫恒

发布于

2019-04-20

更新于

2022-04-23

许可协议

评论