Shell 学习笔记 0x06
1. 位置参数
Shell 中 $n 表示第 n 个参数, $# 表示位置参数的个数:
1 | echo "argc: $#" |
运行:
1 | ./test.sh param1 param2 param3 |
比如执行
command param1 param2,无论在哪里$0都默认是command,只有$1之后的位置参数会发生变化
1.1. 遍历所有位置参数
如果想循环遍历所有参数,这种:
1 | while (( i < $# )); do |
是 Shell 不允许的, Shell 采用一种蹩脚的方式:
1 | echo "0: $0" |
shift 会把从第 1 个到第 $# 个位置参数各往前移一位,而 $0 不会被改变,同时 $# 会减一。比如:
1 | command param1 param2 param3 |
的位置参数是:
commandparam1param2param3
shift 之后会是这样:
commandparam2param3
1.2. 一些特殊的变量
1 | print_params () { |
输出:
1 | ===== $* ===== |
$$ 会被展开为当前进程 PID :
1 | echo $$ |
$RANDOM 会被展开为 1-32767 之间的随机整数:
1 | echo $RANDOM |
2. for
Shell 也有 for ,类似于 Python 的版本:
1 | for variable [in words]; do |
比如:
1 | for i in a b c d; do echo ${i}; done |
Shell 还有类似 C 的版本:
1 | for (( exp1; exp2; exp3 )); do |
相当于:
1 | (( exp1 )) |
比如:
1 | for (( i = 0; i < 5; i = i + 1 )); do |
可以输出五次 foo
3. 更精细的参数展开
3.1. 空变量的展开
${var:-word}:如果var没有定义或为空,则会被展开成word,变量var不会被改变${var:=word}:如果var没有定义或为空,则会被展开成word,变量var也会被定义为word${var:?word}:如果var没有定义或为空,则会退出整个脚本并显示错误信息word${var:+word}:如果var没有定义或为空,则会被展开为空,否则展开为word,变量var不会被改变
1 | echo '===== :- =====' |
运行结果:
1 | ===== :- ===== |
3.2. 变量名的展开
1 | echo ${!XDG*} |
可以展开所有 XDG 开头的所有变量名
zsh 貌似没有这种展开,
!str会被展开成历史指令,比如上一次执行了df -lh, zsh 则会把${!df}展开成${df -lh},然后就会产生错误
3.3. 字符串展开
多用这些展开可以减少类似 cut, sed 之类的额外程序的使用,或许能一定程度上增加便利性,提高运行效率
3.3.1. 切片
类比 Python 的语法
1 | foo="Bash is an sh-compatible command language interpreter" |
输出:
1 | len(foo) = 53 |
也有 Python 一样的负数用法,但需要在负号 - 前面加上空格,来与 ${var:-word} 进行区分:
1 | foo="Bash is an sh-compatible command language interpreter" |
输出:
1 | foo[-20:] = language interpreter |
3.3.2. 截断
还可以取子字符串:
1 | foo="unzip.exe.zip" |
${var#glob} 会把字符串匹配 glob 的部分截掉(从头开始),但只截最短的匹配结果,而 ${var##glob} 会截掉最长的匹配结果,结果:
1 | exe.zip |
${var%glob} 和 ${var%%glob} 与上面的相似,但会从末尾开始截掉文本:
1 | foo="unzip.exe.zip" |
运行结果:
1 | unzip.exe |
3.3.3. 替换
1 | foo="unzip.exe.zip" |
运行:
1 | unrar.exe.zip |
${var/glob/str}:替换第一个匹配项${var//glob/str}:替换所有匹配项${var/#glob/str}:替换字符串开头的匹配项${var/%glob/str}:替换字符串末尾的匹配项
str 也可以为空,来删除匹配项
3.3.4. 大小写转换
1 | declare -u u |
输出:
1 | ABCD |
declare 可以完成转换,但 declare 功能还有很多,更方便的大小写转换可以:
1 | foo="abc" |
输出:
1 | Abc |
${var^} 会使首字符大写, ${var^^} 会全部大写; ${var,} 会使首字符小写, ${var,,} 会全部小写
3.4. 算术展开
1 | echo $(( 114 * 1000 + 514 )) |
3.4.1. 进制
num 默认是十进制, 0num 为八进制, 0xnum 为十六进制, base#num 为 base 进制:
1 | echo $((0377)) # octal |
3.4.2. 运算符
和 C++ 一样,支持 +, -, *, /, %, =, +=, -=, *=, /=, %=, ++, --, ~, <<, >>, &, |, ^, <=, >=, <, >, ==, !=, &&, ||, ?: ,还支持类似 Python 的乘方 **
打印九九乘法表:
1 |
|
1 | 1x1=1 1x2=2 1x3=3 1x4=4 1x5=5 1x6=6 1x7=7 1x8=8 1x9=9 |