echo

  • -n:取消末尾的回车符,不换行。
  • -e:解释特殊字符(如”,\n),如果不适用-e参数,特殊字符会以普通字符的形式输出。

命令组合符

1
2
3
Command1 && Command2 #Command1运行成功后才会运行Command2
Command1 || Command2 #Command1运行失败后才会运行Command2
Command1 ; Command2 #Command1运行结束(不论成功或者失败)后均会运行Command2

模式扩展(参考正则表达式)

无匹配项时不扩展

  • ~:扩展为当前用户的主目录
  • ~+:扩展为当前目录,相当于pwd
  • ?:扩展为任意单个字符,不包括空白符
  • *:扩展为任意数量的字符,包含零个字符
  • [ ]:[ab]可扩展为a与b
  • [start-end]:扩展为连续的范围,例如[a-z]扩展为所有小写字母
  • { }:扩展为大括号内的所有值
  • $:扩展为变量值,如echo $SHELL打印bash的路径

变量

变量创建

变量赋值时双引号中的变量仍保留特殊意义

1
2
3
4
5
6
a=z                     # 变量 a 赋值为字符串z
b="a string" # 变量值包含空格,就必须放在引号里面
c="a string and $b" # 变量值可以引用其他变量的值
d="\t\ta string\n" # 变量值可以使用转义字符
e=$(ls -l foo.txt) # 变量值可以是命令的执行结果
f=$((5 * 7)) # 变量值可以是数学运算的结果

变量读取

1
2
$ echo The total is $100.00
The total is 00.00

在$前加上\转义后:

1
2
$ echo The total is \$100.00
The total is $100.00

Bash脚本

脚本参数

在使用参数时:$ script.sh word1 word2 word3

  • $0:脚本文件名
  • $1~$9:第1~9个参数
  • $#:参数的数量
  • [email protected]:全部参数,使用空格分割
  • $*:全部参数,使用$IFS分割,可自定义
  • $?:上一条语句的运行返回值(0为成功,其他为失败)

条件

  • if:
1
2
3
4
5
6
7
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

echo -n "输入一个1到3之间的数字(包含两端)> "
read character
if [ "$character" = "1" ]; then
echo 1
elif [ "$character" = "2" ]; then
echo 2
elif [ "$character" = "3" ]; then
echo 3
else
echo 输入不符合要求
fi
  • then(if结构的判断条件):
1
2
3
4
5
6
7
8
# 写法一
test expression

# 写法二
[ expression ]

# 写法三,支持正则
[[ expression ]]

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 写法一
if test -e /tmp/foo.txt ; then
echo "Found foo.txt"
fi

# 写法二
if [ -e /tmp/foo.txt ] ; then
echo "Found foo.txt"
fi

# 写法三(支持正则)
if [[ -e /tmp/foo.txt ]] ; then
echo "Found foo.txt"
fi

循环

  • while:
1
2
3
while condition; do
commands
done

例如:

1
2
3
4
5
6
7
#!/bin/bash

number=0
while [ "$number" -lt 10 ]; do
echo "Number = $number"
number=$((number + 1))
done
  • for…in:
1
2
3
4
for variable in list
do
commands
done

例如:

1
2
3
4
5
#!/bin/bash

for i in word1 word2 word3; do
echo $i
done
  • for:
1
2
3
for (( expression1; expression2; expression3 )); do
commands
done

例如:

1
2
3
for (( i=0; i<5; i=i+1 )); do
echo $i
done

函数

  • 定义:
1
2
3
4
5
6
7
8
9
# 第一种
fn() {
# codes
}

# 第二种
function fn() {
# codes
}

例如:

1
2
3
4
today() {
echo -n "Today's date is: "
date +"%A, %B %-d, %Y"
}
  • 参数:
1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
# test.sh

function alice {
echo "alice: [email protected]"
echo "$0: $1 $2 $3 $4"
echo "$# arguments"

}

alice in wonderland
  • 返回值:
1
2
3
function func_return_value {
return 10
}

例如:

1
2
3
$ func_return_value
$ echo "Value returned by function is: $?"
Value returned by function is: 10

可维护性(set)

  • set -u:遇到不存在的变量时报错并且停止执行

脚本:

1
2
3
4
5
#!/usr/bin/env bash
set -u

echo $a
echo bar

运行:

1
2
$ bash script.sh
bash: script.sh:行4: a: 未绑定的变量
  • set -x:运行结果前,输出执行的一行命令

脚本:

1
2
3
4
#!/usr/bin/env bash
set -x

echo bar

运行:

1
2
3
$ bash script.sh
+ echo bar
bar
  • set -e:脚本发生错误时,终止运行

脚本:

1
2
3
4
5
#!/usr/bin/env bash
set -e

foo
echo bar

运行:

1
2
$ bash script.sh
script.sh:行4: foo: 未找到命令
  • set -o pipefail:在管道命令发生错误时,终止运行

脚本:

1
2
3
4
5
#!/usr/bin/env bash
set -eo pipefail

foo | echo a
echo bar

运行:

1
2
3
$ bash script.sh
a
script.sh:行4: foo: 未找到命令
  • 总结:

所有Bash脚本头部均应放置:

1
2
3
4
5
6
# 写法一
set -euxo pipefail

# 写法二
set -eux
set -o pipefail

调试

  • bash -n:不运行脚本,只检查语法错误
  • bash -x:执行每一条命令前,打印该命令

其他

  • >>:重定向输出追加内容 ;>:输出覆盖原有内容
  • <:重定向输入
  • &:指令在后台运行;&&:第一条指令执行成功后才会执行第二条
  • |:管道,第一条指令的输出作为第二条指令的输入;||:第一条指令执行失败后执行第二条指令

参考文献

Bash脚本教程