这里记录了一些个人学习 Shell Script 时遇到的一些问题, 可以作为避免踩坑和速查手册. 如有疑问欢迎留言.
读取参数时,使用 $0..$9 ${10} 等获取参数
其中 $0 是程序名称
add.sh 1 2 3 4 5 6 7 8 9 10 11 12 name=`basename $0 ` echo "the cmd is $0 " echo "the cmd basename is $name " echo "The #1 param is $1 " echo "The #2 param is $2 " SUM=$[ $1 + $2 ] echo "The result is $SUM "
输出
1 2 3 4 5 6 7 ➜ ~ chmod +x add.sh ➜ ~ ./add.sh 1 2 the cmd is ./add.sh the cmd basename is add.sh The #1 param is 1 The #2 param is 2 The result is 3
还有几个特殊的变量可供使用
echo $# 输出参数的个数
echo $* 输出参数变量
echo $@ 输出参数列表(可用 for in 遍历)
下面的例子来判断变量参数是否符合要求
1 2 3 4 5 6 if [ $# -lt 2 ] then echo "please input at least 2 param" fi
使用 shift 命令将参数队列的第一个参数移出 所有参数位置向前移动
sum.sh 1 2 3 4 5 6 7 8 9 10 11 result=0 while [ -n "$1 " ] do result=$[ $result + $1 ] shift done echo "sum of result is $result "
read [-s] [-t timeout] [-n num] [-p prompt] [variables...]
-p prompt 提示语句
-s 静默输入(例如输入密码)
-t timeout 设置输入超时时间,如果超时则以非 0 状态退出
-n num 限制输入字数,如果设置为一则只需要按下一个字母,无需按回车键
variabels 变量名 可以制定多个, 如果不指定会将输入将存入REPLY变量中
1 2 3 4 5 6 echo -n "Enter your name:" read name echo "hello $name ,welcome to my program" exit 0
交互式菜单
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 34 35 36 37 38 39 #!/bin/bash echo "Please Select: 1.Display System Information 2.Display Disk Space 3.Display Home Space Utilization 0.Quit" read -p -n 1 "Enter selection [0-3] >" numif [[ $num =~ ^[0-3]$ ]]; then if [[ $num == 0 ]]; then echo "Program terminated" exit ; fi if [[ $num == 1 ]]; then echo "Hostname :$HOSTNAME " uptime exit fi if [[ $num == 2 ]]; then df -h exit ; fi if [[ $num == 3 ]]; then if [[ $(id -u) -eq 0 ]]; then echo "Home Space Utilization(All Users)" du -sh /home/* else echo "Home Space Utilization($USER )" du -sh $HOME fi fi else echo "Invalid entry." >&2 exit 1 fi
我们在写 shell 脚本时会遇到需要进行手动输入的命令,如 sudo passwd 等需要等待输入密码,在 shell 脚本中如何进行输入呢?
以 passwd username 为例
1 2 3 4 5 6 #!/bin/bash passwd username << EOF 123456 123456 EOF
1 2 3 4 5 6 7 if [ c1 -a c2 ]; then ... fi if [ c1 ] && [ c2 ]; then ... fi
1 2 3 4 5 6 7 if [ c1 -o c2 ]; then ... fi if [ c1 ] || [ c2 ]; then ... fi
参数
作用
-e file
判断 file 是否存在 (exist)
-f file
判断 file 是否存在并且是 file
-d file
判断 file 是否存在并且是 directory
-S file
判断 file 是否存在并且是 socket
-L file
判断 file 是否存在并且是 symbolic link
-r file
判断 file 是否存在并且可读 (readable)
-w file
判断 file 是否存在并且可写 (writeable)
-x file
判断 file 是否存在并且可执行 (executable)
-s file
判断 file 是否存在并且文件大小 (size) 非零
file1 -nt file2
判断 file1 存在并且比 file2 新 (newer than)
file1 -ot file2
判断 file1 存在并且比 file2 旧 (older than)
file1 -ef file2
判断 file1 和 file 2存在并且是同一个文件 (exist & same file)
string
判断 string 是空字符串
-n string
判断 string 长度为非零 (non-zero)
-z string
判断 string 长度为零 (zero)
s1 = s2
判断字符串 s1 和 s2 相同
s1 != s2
判断字符串 s1 和 s2 不同
s1 < s2 / s1 > s2
判断字符串 s1 的二进制值比 s2 小 / 大
! expiression
取表达式的非值
expiression1 -a expression2
判断表达式1 和(and) 表达式2 都为真
expiression1 -o expression2
判断表达式1 或(or) 表达式2 为真
注意:
如果文件是一个符号链接 (symbolic link),它将会指向链接的真实文件进行判断,除非指定了 -L 或 -n 参数.
当 -a 和 -o 同时使用时,-a 的运算优先级比 -o 高.
判读符号 [] 的使用方法与 test 命令一致。
[] 方括号内的每个元件都要以空格分隔,这包括方括号本身。
[ -z foo ] [ "$name" == "foo bar" ]
如果需要引入变量,变量最好使用双引号包裹,否则变量中出现的空格将会作为判断符号的元件被分隔。
试着体会 [ -z "foo bar" ] 和 [ -z foo bar ] 的区别
1 2 3 [ -z abc -a -w file] # => true [ (-z abc) -a (-w file)] # => true [ -z abc ] && [ -w file] # => false
参数
作用
-e
判断文件是否存在
-v
判断命令是否存在
if
这是shell的基本形式,要求命令返回0表示真,非0表示假,比较简单。例如:
1 2 3 if cmd; then echo "True" fi
if [ ] 这是shell的扩展形式,使用 [] 进行条件测试。例如:
1 2 3 if [ $a -eq $b ]; then echo "a 等于 b" fi
if [[ ]] 这是shell的新形式,使用 [[ ]] 进行条件测试。它有以下优点:
支持正则表达式匹配
不需要在条件表达式内部加空格
支持 && 和 || 逻辑操作
支持字符串比较
例如:
1 2 3 4 5 6 7 if [[ $a = "b" ]]; then echo "a 等于 b" fi if [[ $a -eq $b ]] && [[ $c -gt $d ]]; then echo "条件满足" fi
综上,如果shell版本支持,推荐使用 if [[ ]] 形式进行条件判断,它有更多特性和优点。if [ ] 形式虽然也可用,但需要注意内部空格问题。if 命令形式最简单,但实用性较差。
函数的定义格式如下
1 2 3 4 [function] funname [()] { action; [return int;] }
1 2 3 4 5 6 7 8 9 function fn { echo "hello world!" return 0 } say_hi() { echo $1 } say_hi jack
参数
说明
$1 $10 ${11}
第 1, 10, 11 个参数
$#
传递到脚本或函数的参数个数
$*
以一个单字符串显示所有向脚本传递的参数
$@
与 $* 相同,但是使用时加引号,并在引号中返回每个参数。
$$
脚本运行的当前进程 ID 号
$!
后台运行的最后一个进程的 ID 号
$-
显示 Shell 使用的当前选项,与 set 命令功能相同。
$?
显示最后命令的退出状态。0 表示没有错误,其他任何值表明有错误。
1 2 3 4 # 获取当前 ref 名 ref_name=$(git symbolic-ref -q HEAD) # => refs/heads/master # 利用替换命令 branch_name=${ref_name##refs/heads/} # => master