介绍Bash
字符串操作
1 | s=abcdefghijk |
长度
1 | # echo ${#s} |
slice
1 | # echo ${s:1:3} |
从头部的最长匹配,删除matching部分
1 | # echo ${t##a*b} |
从头部最短匹配
1 | # echo ${t#a*b} |
失配
1 | # echo ${t#m*m} |
尾部匹配改成%
变量
$?
上一个指令退出码$$
进程ID,等于BASHPID$_
上一个命令的最后一个参数$!
最近一个后台执行的异步命令(也就是后面加&的)的进程 ID$0
shell的名称,或者运行的shell脚本的名称,大于等于10的用${10}等$#
参数个数$@
空格分割的全部参数
可以循环 $@1
2
3for i in "$@"; do
echo $i
done$*
$IFS分割的全部参数,貌似要echo "$*"
才行。IFS是Internal Field Separator
注意#@
和$*
的行为在加引号之后不一样,"$*"
会作为一个整体~+
pwd~-
OLDPWD的值~user
user用户的目录
注意区分makefile的参数$@
扩展成当前规则的目的文件名,$<
扩展成依赖列表中的第一个依赖文件,而$^
扩展成整个依靠的列表(除掉了里面所有重复的文件名)。
下面是一个供展示的bash脚本
1 | echo $0 |
表达式
${}表达式
也称为Parameter expansions规则${parameter:-word}
:如果parameter是unset或者null,那么表达式的值是word
的展开。${parameter:=word}
:返回值同上,但是parameter的值会被设置成word
。${parameter:?word}
:如果是unset或者null,则表示一个错误。错误可能被写到stderr,并且通过非0返回值返回。${parameter:+word}
:如果是unset或者null,则用null替换;否则用word替换。也就是不为空替换。
注意,我们需要区分$(command)
,这个表示用command的output进行替换,等同于反引号backquote的写法。
命令
source
在当前sh执行脚本,简写是.
。sh会创建一个新的。--
表示参数是传给后面的
例如cargo test -- --nocapture
,则--nocapture
并不是传给cargo test的,而是传给cargo test生成的二进制的。
控制
if
后面可以跟任意数量的命令。这时,所有命令都会执行,但是判断真伪只看最后一个命令,即使前面所有命令都失败,只要最后一个命令返回0,就会执行then的部分。
1 | $ if false; true; then echo 'hello world'; fi |
if结构的判断条件,一般使用test命令,有三种形式。第三种形式还支持正则判断,前两种不支持。expression 为真,test命令执行成功(返回值为0);expression为伪,test命令执行失败(返回值为1)。
1 | # type -a [[ |
写法一
1
test expression
写法二
注意,因为中括号实际上是一个命令,所以左右都要有空格1
[ expression ]
写法三
1
[[ expression ]]
这种写法还支持正则表达式正则表达式
[[ expr =~ regex ]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15MIN_VAL=1
MAX_VAL=100
INT=50
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if [[ $INT -ge $MIN_VAL && $INT -le $MAX_VAL ]]; then
echo "$INT is within $MIN_VAL to $MAX_VAL."
else
echo "$INT is out of range."
fi
else
echo "INT is not an integer." >&2
exit 1
fi
还可以使用bash自己的&&
,这个遵循短路原则
1 | if [ condition ] && [ condition ]; then |
等同样例
1 | [[ -d "$dir_name" ]] && cd "$dir_name" && rm * |
等同于
1 | if [[ ! -d "$dir_name" ]]; then |
函数
函数优于脚本,低于别名
1 | hello() { |
函数与变量相关的$@
、$0
等,与脚本一致。