shell脚本速查

date: 2013.05.23; modification:2018.05.06

目录:

1 变量

var="hello"

len=${#var} # 获得字符串长度

1.1 特殊变量

2 数组

2.1 声明

declare -a myarray # myarray被当作数组名

bash中可以不声明, 直接定义.

2.2 定义

第1种方式: 数组元素内部没有空格

myarray=( value1 value2 value3 ... )
或:
myarray="one two three"

第2种方式: 数组元素内部包含空格

cmds[0]="git checkout master"
cmds[1]="git pull"

2.3 访问

${myarray[key]}   # 访问单个数组元素. 例如: cmds[1]
${myarray[*]}     # 访问所有元素
${myarray[@]}     # 访问所有元素(每个元素作为一个参数, 即使包括空格)

2.4 删除

unset myarray[1]  # 删除数组中第一个元素
unset myarray     # 删除整个数组

2.5 计算数组长度

${#myarray[*]}    # 获取数组长度(元素总个数).
${#myarray[@]}    # 获取数组长度(元素总个数).
${#myarray[0]}    # 获取元素0的长度.

2.6 数组截取

${myarray[*]:1}   # 截取: 从下标为1的元素到最后一个
${myarray[*]:2:3} # 截取: 从下标为2(含2)的元素开始, 截取3个元素

2.7 子串删除与替换

会将所有的元素中的匹配到的子串删除/替换.

array=("zero" "one" "two" "three" "four" "soho")

#删除:
echo ${array[@]#t*e}   # 从字符串的起始开始最短匹配: "t*e", 这将匹配到"thre". 将显示: zero one two e four soho
echo ${array[@]##t*e}  # 从字符串的起始开始最长匹配, 这将匹配到"three". 将显示: zero one two four soho
echo ${array[@]%o*}    # 从字符串的结尾开始最短匹配. 将显示: zer tw three f soh
echo ${array[@]%%o*}   # 从字符串的结尾开始最长匹配. 将显示: zer tw three f s

#替换:
echo ${array[@]/e/+}   # 从字符串的任意位置开始最短的匹配并替换. 将显示: z+ro on+ two thr+e four soho
echo ${array[@]//e/+}  # 从字符串的任意位置开始最长的匹配并替换. 将显示: z+ro on+ two thr++ four soho
echo ${array[@]/#o/+}  # 从字符串的起始开始匹配并替换. 将显示: zero +ne two three four soho
echo ${array[@]/%o/+}  # 从字符串的结尾开始匹配并替换. 将显示: zer+ one tw+ three four soh+

3 函数

    function func1()
    {
         echo `expr $1 \+ $2`
         return `expr $1 - $2`
    }

    func1 11 1          # 显示输出为12

    ret=`func1 11 1`    # 无显示输出
    echo $?             # 显示输出为10
    echo $ret           # 显示输出为12

说明: * func1中return的值并不是存在变量ret中, 而是在$?中, 这点与大多语言不同. * 被赋值的变量ret, 其实存的是func1中用echo, cat等终端打印的内容.

4 条件测试

4.1 文件

  1] -r file      : 可读为真
  2] -w file      : 可写为真
  3] -x file      : 可执行为真
  4] -f file      : 存在且是普通文件为真
  5] -d file      : 存在且是目录文件为真
  6] -p file      : 存在且是命名的FIFO文件为真
  7] -b file      : 存在且是块设备文件为真
  8] -c file      : 存在且是字符设备文件为真
  9] -s file      : 存在且长度>0为真
  10]-t 文件描述字: 文件打开且其文件描述字是与终端设备相关的为真. 默认的"文件描述字"是1.

4.2 字符串

  1] -z s1   : 长度为0为真
  2] -n s1   : 长度>0为真
  3] s1      : 不是空串则为真
  4] s1 = s2 : 串相等为真
  5] s1 != s2: 串不等为真
  6] s1 <  s2: 字典顺序s1在s2前为真
  7] s1 >  s2: 字典顺序s1在s2后为真

4.3 数值

  1] n1 -eq n2: 等于为真
  2] n1 -ne n2: 不等为真
  3] n1 -lt n2: 小于为真
  4] n1 -le n2: 小于等于为真
  5] n1 -gt n2: 大于为真
  6] n1 -ge n2: 大于等于为真

4.4 逻辑运算符

  1] !: 逻辑非
  2] -a: 逻辑与
  3] -o: 逻辑或

4.5 特殊条件测试

  1] :: 不做任何事, 退出值为0(真).
  2] true: 总为真, 退出值为0.
  3] false: 总为假, 退出值为255.

5 分支与循环

5.1 if

if 条件; then
    cmd1
else
    cmd2
fi

5.2 case

case 字符串 in
    模式1) cmd1
        ;;
    模式2) cmd2
        ;;
esac

5.3 while

while 测试条件
    cmd
done

可以使用break

5.4 until

until 测试条件
do
    命令表
done

5.5 for

for 变量 [in 值表]
do
    cmd
done

6 shell输入与输出

6.1 echo

选项:

-e: 翻译反斜杠'\'的转意.
-E: 不翻译反斜杠'\'的转意.

-e的转意:

\c: 不换行.
\n: 换行.
\r: 回车.
\t: tab.
\v: 纵向tab(不回车的换行).

6.2 read

用法: read var1 var2 (以空格为分隔, 回车为结束)

如果不能一一对应, 多余的全部给最后一个变量.

6.3 cat

用法1: 显示

cat file1
cat file1 | more
cat -v file1 #(显示控制字符)

用法2: 合并文本文件

cat file1 file2 > file_tar

用法3: 简单文本录入器

cat > file1 #(键盘读入字段, 输入到file1, 以<Ctrl+D>结束)

6.4 标准输入, 输出, 错误输出

标准输入, 输出, 错误输出分别为0, 1, 2

cmd > file1 2>&1 # 标准输出和标准错误一起重定向.
cmd > /dev/null  # 重定向到垃圾箱
cat file1.txt file2.txt 1>file3.out 2>file4.err # 标准输出和标准错误一起使用.

6.5 tee

把输出的一个副本输送到标准输出, 另一个副本拷贝到相应的文件中.

选项: -a: 追加.

6.6 管道

time=`date|awk '{print $5}'|sed -e 's/://g'`
并且awk和sed一次完成不了的, 可以分多次一直管道, 直到完成.

7 算术运算

7.1 简单运算(不支持浮点)

a=`expr ${a} + 1`

let a=1+2
let a++     # 或 let a--
let a+=6

a=$[$b + 1]

7.2 复杂运算

echo "3.14 * 2.54" | bc
echo "scale=2;3/8" | bc  # scale=2参数表示小数位为2. 参数由分号分割.
echo "obase=16;ibase=2;0101010110101010" | bc  # 进制转换
echo "10^10" | bc  # 计算平方
echo "sqrt(100)" | bc  # 计算平方根, 结果为整数
echo "sqrt(100.01)" | bc  # 计算平方根, 结果为小数, 小数位数为后面.01的位数相同.

8 常用命令与语句

8.1 exit

exit [n]  : n缺省则为最后一条命令的退出值.

8.2 select

select id [in word ...]
do
    cmd
done

8.3 sort

说明: 一般处理类似表格的文本文件. 将其一列一列的进行分类, 切割, 合并等.

选项:

-c: 测试是否已经分类.
-m: 合并两个分类的文件.
-u: 省略重复行.
-o file1: 将结果存入file1.
-b: 忽略前导空白.
-n: 按数字分类. 如: 123比89大.
-t: 制定分隔符.
-r: 逆序排列.
-ki: i指示第i域开始分类. i从1开始数.

9 shell中的括号

()和{}都是对一串的命令进行执行, 但有所区别:

10 小技巧

10.1 获取随机数

echo $RANDOM # 生成0-32767之间的整数随机数

10.2 获取某程序的进程号

pgrep vim

10.3 获取进程的环境

cat /proc/$$/environ | tr '\0' '\n'

10.4 如何kill子进程

xscreensaver_deactivate &
child=$!
xterm ...
kill -TERM "$child"
wait "${child}" 2>/dev/null

说明: xscreensaver_deactivate是个在后台一直执行的程序, child=$!获取它的PID, 当xterm ...执行后, 向它发送信号, 使其退出.

10.5 文件名与扩展名

10.5.1 获取文件名(含扩展名)

basename dir1/dir2/example.tar.gz

将得到: example.tar.gz

10.5.2 获取文件名(不含扩展名)

basename dir1/dir2/example.tar.gz .tar.gz

将得到: example

10.5.3 获取路径名(不含扩展名)

dirname dir1/dir2/example.tar.gz

10.5.4 另一种方法

FILE="aaa.bbb.example.tar.gz"

echo "${FILE%.*}"
将得到: aaa.bbb.example.tar, 即将最右边的一个点后面的作为扩展名.

echo "${FILE%%.*}"
将得到: aaa, 即将最左边的一个点后面的全都作为扩展名.

echo "${FILE#*.}"
将得到: bbb.example.tar.gz, 即将最左边的一个点后面的全都作为扩展名.

echo "${FILE##*.}"
将得到: gz, 即将最右边的一个点后面的作为扩展名.

10.5.5 逐行读取文件

cat /etc/passwd | while read line do echo $line done

10.6 捕获ctrl-c等信号

使用命令kill -l可以列出系统的信号名称, 通常我们需要忽略的信号有四个, 即: HUP, INT, QUIT, TSTP, 也就是信号1, 2, 3, 24; QUIT即信号2就是表示操作CTRL+C;

trap的使用格式为:

trap 操作 信号名称

例如:

trap "echo hello mike" 2

表示捕获到信号2(ctrl+c)时并不会退出而是会 执行命令echo hello mike;

同样可以用: trap "" 2 表示什么也不操作.

使用 trap 2 来使其恢复默认设置.

10.7 显示/隐藏光标

隐藏:

echo -e "\033[?25l"

显示:

echo -e "\033[?25h"

10.8 tput设置光标

tput lines : 显示终端的行数
tput cols  : 显示终端的列数
tput cup line_num col_num : 定位光标到line_num行, col_num列.

10.9 打印华丽的分割线(同终端等长)

printf "%*s" $COLUMNS | tr " " "="

10.10 在文件头添加行

# 在第一行之后添加一行. 其中的反斜杠用来插入后面的空格, 否则空格都会被认作1a命令后的间隔, 从而不会被插入.
sed -e "1a \    * hello" -i my.txt

如果想在第一行之前添加, 则是1i

11 参考资料

http://bbs.chinaunix.net/thread-1779167-1-1.html