概述

​ Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

​ Shell 脚本(shell script),是一种为 shell 编写的脚本程序。

set 命令

  • set -e表示一旦脚本中有命令的返回值为非0,则脚本立即退出,后续命令不再执行;
  • set -o pipefail表示在管道连接的命令序列中,只要有任何一个命令返回非0值,则整个管道返回非0值,即使最后一个命令返回0.
  • set -u遇到不存在的变量就会报错,并停止执行。效果等同 set -o nounset

常用特殊变量

变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2
$# 传递给脚本或函数的参数个数
$* 传递给脚本或函数的所有参数
$@ 传递给脚本或函数的所有参数。被双引号(” “)包含时,与 $* 稍有不同
$? 上个命令的退出状态,或函数的返回值。成功返回0,失败返回1
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID

$*$@ 都是将参数一个一个返回 。
"$*"将所有参数当做一个整体字符串返回 , "$@"将参数一个一个返回。

数值判断

命令 含义
-eq 等于
-ne 不等于
-gt 大于
-lt 小于
-ge 大于等于
-le 小于等于
1
2
3
4
# 判断脚本传入参数个数是否为0
if [ $# -gt 0 ]; then
echo "Parameter Error!"
fi

逻辑判断

命令 含义
-a 逻辑与
-o 逻辑或
! 逻辑非
1
2
3
if [ "None" = MODEL -a "None" = IMAGE ]; then
echo "Parameter Error!"
fi

字符串判断

命令 含义
= 字符串是否相等
!= 字符串是否不相等
-n 字符串的长度是否不等于0
-z 字符串的长度是否等于0
1
2
3
4
5
STRING=""
if [ -n "${STRING}" ]; then
echo "Everything"
fi
# 注意 若${STRING}不加双引号, 则也是认为字符串长度大于0

去除字符串的双引号

1
${str} | sed 's/\"//g'

shell 判断文件是否存在

文件/目录判断

命令 含义
-r 文件是否存在且可读
-w 文件是否存在且可写
-s 文件是否存在且长度非0
-f 文件是否存在且是普通文件
-d 目录是否存在
1
2
3
4
5
if [ ! -d "/data/" ];then
mkdir /data
else
echo "文件夹已经存在"
fi

提取文件名和目录名

从路径中获取文件名

1
2
3
PATH="/data/local/tmp/file.txt"
echo ${PATH##*/}
# 结果为 file.txt
1
2
3
4
5
6
PATH="/data/local/tmp/file.txt"
echo $(basename ${PATH})
# 结果为 file.txt

echo $(basename ${PATH} .txt)
# 结果为 file

从路径中获取文件后缀名

1
2
3
4
5
6
7
8
PATH="/data/local/tmp/file.tar.gz"
# 返回从左边算起的最后一个'.'(不含该字符)的右边的内容
echo ${PATH##*.}
# 结果为 gz

# 返回从左边算起第一个'.'(不含该字符)的右边部分的内容
echo ${PATH#*.}
# 结果为 tar.gz

从路径中获取文件所在目录路径

1
2
3
4
5
6
PATH="/data/local/tmp/file.txt"
echo ${PATH%/*}
# 结果为 /data/local/tmp

echo ${PATH%%.*}
# 结果为 /data/local/tmp/file
1
2
3
4
5
6
7
PATH="/data/local/tmp/file.txt"
echo $(dirname ${PATH})
# 结果为 /data/local/tmp

PATH="/data/local/tmp
echo $(dirname ${PATH})
# 结果为 /data/local

变量替换

命令 含义
$variable 保存在variable中的值
${variable} 保存在variable中的值
${variable}:-string 如果variable值为非空, 则值为variable, 否则为string
${variable}:+string 如果variable值为非空, 则值为string, 否则为空
${variable}:=string 如果variable值为非空, 则值为variable, 否则为string且variable的值设为string
${variable}?string 如果variable值为非空, 则值为variable否则显示string并退出

作用: 使用户能够检查变量的值并根据选项改变它的值。

数组遍历

for循环

带数组下标

1
2
3
4
5
MODELS=("AAA" "BBB" "CCC")
for ((i = 0; i < ${#MODELS[@]}; i++))
do
echo $i ${MODELS[i]}
done
1
2
3
4
5
MODELS=("AAA" "BBB" "CCC")
for i in "${!MODELS[@]}"
do
printf "%s\t%s\n" "$i" "${MODELS[$i]}"
done

不带数组下标

1
2
3
4
5
6
# @ 可用 * 替代
MODELS=("AAA" "BBB" "CCC")
for MODEL in ${MODELS[@]}
do
echo $MODEL
done

While循环

1
2
3
4
5
6
7
8
9
MODELS=("AAA" "BBB" "CCC")
i=0
while [ $i -lt ${#MODELS[@]} ]
#当变量(下标)小于数组长度时进入循环体
do
echo ${MODELS[$i]}
#按下标打印数组元素
let i++
done

解析脚本传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/bin/sh

set -e

current_dir=$(cd `dirname $0`; pwd)

USAGE_LINE="Usage: $0 [OPTION] [SELECT]\n \
--input-model\t\t测试模型路径\n \
--input-picture\t测试模型的输入数据文件\n \
--help\t\t\t帮助\n \
e.g: $0 --input-model=./test.pb --input-picture=./test.jpg \
"

for opt in "${@}"; do
case $opt in
--input-model=*)
export input_model="$(echo "$opt" | cut -d '=' -f 2-)"
;;
--input-picture=*)
export input_picture="$(echo "$opt" | cut -d '=' -f 2-)"
;;
--help)
echo ${USAGE_LINE}
exit
;;
*)
echo ${USAGE_LINE}
exit
;;
esac
done

echo ${input_model} ${input_picture}

格式化输出

  • 输出类型

    • %ns:输出字符串。n 是数字,指代输出几个字符。
    • %ni:输出整数。n 是数字,指代输出几个数字。
    • %m.nf: 输出浮点数。m 和 n 是数字,指代输出的整数位数和小数位数。如 %8.2f 代表共输出 8 位数,其中 2 位是小数,6 位是整数。
  • 输出格式

    • \a: 输出警告声音;
    • \b:输出退格键,也就是 Backspaced 键;
    • \f:清除屏幕;
    • \n:换行;
    • \r:回车,也就是 Enter 键;
    • \t:水平输出退格键,也就是 Tab 键;
    • \v:垂直输出退格键,也就是 Tab 键;
  • 示例

    • 有这样一个文本 tmp.txt

      1
      2
      3
      4
      ID Name PHP Linux MySQL Average
      1 Liming 82 95 86 87.66
      2 Sc 74 96 87 85.66
      3 Gao 99 83 93 91.66
    • 格式化输出

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      printf '%s\t %s\t %s\t %s\t %s\t %s\t\n' $(cat tmp.txt)
      # 输出结果
      ID Name PHP Linux MySQL Average
      1 Liming 82 95 86 87.66
      2 Sc 74 96 87 85.66
      3 Gao 99 83 93 91.66

      printf '%i\t %s\t %i\t %i\t %i\t %.2f\t\n' $(cat tmp.txt | grep -v Name)
      # 输出结果
      1 Liming 82 95 86 87.66
      2 Sc 74 96 87 85.66
      3 Gao 99 83 93 91.66