Shell 学习笔记 0x04

Shell 学习笔记 0x04

RayAlto OP

1. if

Shell 中 if 的语法是:

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

如果 if 后面 commands 的返回值为 0 ,则执行 then 后面的 commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh

foo () {
return 0
}

bar () {
return 1
}

if foo; then
echo 'foo'
fi

if bar; then
echo 'bar'
fi

输出:

1
foo

也可以折成一行写,但 then 后面的 commands 后面也要用 ; 隔开:

1
if bar; then echo 'bar'; fi

2. test

常见格式:

1
2
test expression
[ expression ]

test 会根据 expression 的 true/false 来返回 0/1 ,这样就可以结合 if 来使用了:

1
2
3
4
5
6
7
8
9
10
11
foo=114514

if [ ${foo} = 114514 ]; then
echo ok
fi

# ↑↓两种写法等价

if test ${foo} = 114514 ; then
echo ok
fi

2.1. 文件表达式

表达式返回 0 时的情况
file1 -ef file2inode 相同的两个硬链接
file1 -nt file2file1 的修改时间比 file2 的更晚( file1file2 新)
file1 -ot file2file1 的修改时间比 file2 的更早( file1file2 旧)
-e filefile 存在
-f filefile 存在且是一个普通文件
-s filefile 存在且不是一个空文件
-d filefile 存在且是一个目录
-S filefile 存在且是一个 socket
-h file/-L file存在且是一个符号链接
-p filefile 存在且是一个命名管道
-b filefile 存在且是一个块(设备)文件
-c filefile 存在且是一个字符(设备)文件
-g filefile 存在且设置了 setgid
-u filefile 存在且设置了 setuid
-k filefile 存在且设置了 sticky
-r filefile 存在且用户有读取权限
-w filefile 存在且用户有写入权限
-x filefile 存在且用户有执行权限
-G filefile 存在且 GID 代表一个有效的组
-O filefile 存在且 UID 代表一个有效的用户
-t fdfd 是一个被打开的 fd

比如:

1
2
3
if [ -x /bin/sh ]; then
echo ok
fi

但如果涉及到展开,最好用 "" 包住,因为:

1
2
3
if [ -e ]; then
echo ok
fi

同样会输出 ok ,但:

1
2
3
if [ -e "" ]; then
echo ok
fi

则不会输出 ok ,标准一点的写法是:

1
2
3
if [ -e "${file}" ]; then
echo ok
fi

2.2. 字符串表达式

表达式返回 0 时的情况
str/-n strstr 长度大于零
-z strstr 长度等于零
str1 = str2/str1 == str2字符串相同
str1 != str2字符串不同
str1 > str2ASCII (POSIX) 排序 str1 > str2
str1 < str2ASCII (POSIX) 排序 str1 < str2

>< 需要用 ""/'' 包围或用 \ 转义,因为 Shell 会把 >< 当作重定向符

1
2
3
4
5
6
7
[ ]                  # 1
[ "" ] # 1
[ " " ] # 0
[ -z ] # 0
[ -z "" ] # 0
[ "foo" == "foo" ] # 0
[ "foo" '<' "bar" ] # 1

2.3. 整数表达式

表达式返回 0 时的情况
int1 -eq int2int1 == int2
int1 -ne int2int1 != int2
int1 -le int2int1 <= int2
int1 -lt int2int1 < int2
int1 -ge int2int1 >= int2
int1 -gt int2int1 > int2
1
2
3
4
5
[ 114514 -eq 114514]       # 0
[ "114514" -eq "114514" ] # 0
[ $(( 1 + 1 )) -eq 2 ] # 0
foo=1
[ $((${foo}+1)) -eq 2 ] # 0

3. Bash 扩展

3.1. 更强大的 test

1
2
3
[[ 114514 == 114* ]]                  # 0 ( == 额外支持通配符)
[[ 114514 =~ ^[0-9]*$ ]] # 0 (增加 =~ 支持 POSIX extended regular expression )
[[ $((1+1)) == 2 && $((2+2)) == 4 ]] # 0 (增加 && || 等运算符的支持)

3.2. 更强大的整数运算

1
2
3
4
5
foo=1
((3)) # 0 (结果为非 0 值时返回值为 0 ,否则为 1 )
((0)) # 1
(( ${foo} == 1 )) # 0 (支持一套完整的整数运算符)
(( foo == 1 )) # 0 (因为这是 Shell 语法的一部分,且仅用于整数运算,所以变量会被识别并自动展开)

test[ ] 本质上是一个程序(来自 coreutils ),所以所有表达式都被看作 Shell 参数,所以 <, >, (, ) 等字符需要进行转义,而 [[ ]](( )) 是 Shell 语法的一部分,里面的表达式会被视作 Shell 语法,所以不需要进行转义。

3.3. 逻辑运算符

逻辑运算符test[[ ]](( ))
AND-a&&
OR-o||
NOT!!