第11章 结构化命令
if-then
testuser=rich if grep $testuser /etc/passwd ;then echo The bash file for user $testuser are: ls -a /home/$testuser/.b* fi
if-then-else
if comA; then comB else comC fi if com1;then com2 elfi com3;then com4 fi
test 测试判断
if test condition <==> if [condition] then commands fi 数值比较 A -eq B = [ $var1 -gt 5 ] -ge >= [ $var1 -eq $var2 ] -gt > -le <= -lt < -ne != test无法处理变量中的浮点值 字符串比较 相等 [ "$USER" = "$testuser" ] 转义大小于号 [ $var1 \> $var2 ],否则会重定向 test中 用ASCII顺序 T < t sort中 用系统本地化设置 t < T 大小: 应在进行字符串运算时判断是否为空 if [ -n "$var1" ] 是否非空 if [ -z "$var1" ] 是否为空 未被定义过的字符串长度为0 文件比较 -e file 文件存在? -s 存在&非空? -d.-f 目录,文件 -r. -w.-x可读可写可执行 -O 属当前用户所有? -G文件默认组与当前用户same? A -nt B A 比 B 新 -ot 旧 双方括号 模式匹配 if [[ $USER == r* ]] 复合条件测试 [cond1] && [cond2] <==> -a [cond1] || [cond2] <==> -o 双尖括号 if (( $var1 ** 2 > 90 ));then (( var2 = $var1 ** 2)) <==> var2=$[$var1 ** 2] fi case case $USER in rich|bar) echo ;; testing) echo ;; *) echo ;; esac
第12章 循环
for var in list
do
commands
done
读取列表中的复杂值
for test in I don\'t know if "this'll" work
do
echo $test
done
当包含空格时,双引号括起来
./test.sh
I
don't
know
if
this'll
work
从变量读取列表
list="AB CD EF"
list1=$list"GH JK"
for i in $list1
do
echo $i
done
从命令读取
file="/etc/passwd"
for i in cat $file
do echo "$i" done 分隔符 IFS.old=$IFS IFS=$'\n' IFS=$IFS.old 通配符读取目录 for file in $HOME/.b* do if [ -f "$file" ] done 双引号防止文件名或目录名中有空格 c 风格 for((a=1;a<10;a++)) do commA done while [ $var1 -gt 0 ] do var1=$[ $var1 - 1 ] <==> ((var1 = $var1 - 1)) done 在while中若定义多个测试命令,则取最后一个测试命令的退出状态码为执行条件 until 与while相反, 当$? != 0时,执行 在循环处理文件数据时 可在外部循环中,设置IFS=$'\n'获取一行 在内部循环中,eg:/etc/passwd IFS=:获取单个信息 break n跳出n层循环 处理输出 for(()) do done > test.log 也可以对输出排序 done | sort
第13章 获取输入
echo -n "Enter your name" read name echo "hello name" 或者 read -p "Enter your name:" first last 多余的变量分配给最后一个变量 -n移除了字符串末尾的换行符 若read 行不指定变量,则read将收到的数据放到环境变量REPLY中 超时: -t指定计时器 超时后返回非零退出状态 if read -t 5 -p "Please enter your name:" name then commA else commB fi 输入字符计数 -n1 按下单字符无需换行 read -n1 -p " Do you want to continue [Y/N]?" answer case $answer in Y/y) echo ; N/n) echo ; 隐藏输入: read -s -p "Enter your password" passwd 从文件中读取: cat test | while read line do done 脚本获取外部参数 获取外部输入参数时,使得 $1,$2 shell会自动识别,num或string 当有输入含空格的参数时,需引号圈起来 当参数个数大于9时,${10}, ${11} 读取程序名,不是完整的路径名 name=` basename $0 ` 可实现基于不同的脚本来执行不同的命令脚本。 需测试参数个数: if [ -n "$1" ] $1 存在或者不存在 参数计数: $# if [ $# -ne 2 ] 最后一个参数: ${$#}错误的方式,因为在{}内不能使用$ ${!#} 对 抓取参数: $* 会将所有参数当成单个参数 $@ 会单独处理每个参数 移动变量 shift将所有参数左移 当参数被移除后,值会被丢失且无法恢复。 while [ -n "$1"] do commA shift done 处理选项:将 while+shift+case 混合使用 -- 一般分隔选项和参数
第14章 重定向错误
只重定向错误: ls -sail badfile 2>test4 将错误重定向到 test4,标准输出定向到终端显示器
ls -al test test2 2>test3 1>test4
若重定向到同一个文件:&> shell 会给予错误消息更高的优先级,所以显示在开头。
在脚本中重定向到输出 (临时和永久)
临时重定向 脚本中 echo "This is an error" >&2 运行时 ./test 2>test9 永久重定向 脚本内部 exec 1> testout exec 2> testerror 一旦重定STDOUT或STDERR,将无法轻易回复 脚本中重定向输入: exec 0test echo " " >&3 正确的重定向输出文件描述符: exec 3>&1 exec 1>testout exec 1>&3 恢复文件描述符1 理解: a3=a1 a1=t a1=a3 正确的重定向输入文件描述符 exec 6<&0 exec 0 testfile read line <&3 echo " " >&3 回因为覆盖而产生混乱 关闭文件描述符 exec 3>&- 若关闭后在之后shell脚本命令中打开,则会产生一个新文件来替换已有文件, 所以新的输出会覆盖已有文件 列出打开的文件描述符 #lsof -a -p $$ bash 27677 sholck 0u CHR 136,1 0t0 4 /dev/pts/1 bash 27677 sholck 1u CHR 136,1 0t0 4 /dev/pts/1 bash 27677 sholck 2u CHR 136,1 0t0 4 /dev/pts/1 bash 27677 sholck 255u CHR 136,1 0t0 4 /dev/pts/1 阻止命令输出: /dev/null 任何重定向到该位置的数据都会丢掉 将/dev/null作为输入文件来清空文件内容 cat /dev/null > testfile 用来清除日志。 记录消息tee stdout----->STDOUT | |------> file date | tee testfile date | tee -a testfile 追加 创建临时文件 系统会在启动时自动删除/tmp目录下的文件 任何用户都有在/tmp 读写的权限 创建本地当前目录临时文件: #mktemp testing.XXXXXX testing.hOIz4y 在/tmp下创建临时文件 #mktemp -t testing.XXXXXX /tmp/testing.H
谦让度
VU3BI 创建临时目录: #mktemp -d dir.XXXXXXX dir.ljpG8IU
第15章 定时处理与信号
定时
at -f test 6:25 > /dev/tty2 列出等待中的at作业:atq at -l at -d 删除at作业 at -c 1查看at作业内容 定期执行脚本 cron 时间表 min hour dayofmonth month dayofweek command 15 16 * * 1 command crontab -l 列出已有时间表 cron 列表 /etc/cron.daily /etc/cron.monthly 若需每天运行一次,将脚本复制到daily目录 anacron 运行错过的作业 根据时间戳来决定作业是否被运行过。/var/spool/anacron.monthly anacron时间表 period 多久运行一次 delay 开机后延迟多少分钟运行错过的脚本 identifer command 启动运行时 开机脚本 /etc/rc#.d /etc/init.d /etc/init.d/rc.d $HOME/.bash_profile -->登录shell $HOME/.bashrc -->启动shell /etc/bashrc --->所有用户
处理信号
1.SIGHUP 挂起 2.SIGINT 3.SIGQUIT 9.SIGKILL 15.SIGTERM 终止进程 17. SIGSTOP 停止进程 18. SIGTSTP shell默认忽略SIGUIT SIGTERM Ctrl+c SIGINT Ctrl+z SIGTSTP 暂停 ps au 查看已停止的作业 捕捉信号
谦让度
trap "echo 'Sorry! I have trapped Ctrl+c'" SIGINT SIGTERM 捕捉脚本退出 trap "echo byebye" EXIT 移除捕捉 trap -EXIT 当后台进程在运行时,仍会使用终端来显示STDOUT与STDERR的消息 如果进程会话退出,后台进程也会退出
脱离终端+作业控制+谦让度
在非控制台下运行脚本 nohup ./test1 & 阻断发送给该进程的SIGHUP信号 因为已解除终端和进程的关联,故将STDOUT与STDERR重定向到名为nohup.out的文件中。 作业控制 $$表示该脚本的PID jobs 查看作业 [1]+ 默认作业 [2] - 下一个默认作业 只能有一个+和一个-作业 重启停止作业 后台 bg 2->作业号 前台 fg 1 谦让度 nice -n 10 ./test4 > testout & -n 指定优先级 renice 改变已运行进程的优先级 renice 10 -p 29504 29504 is process-id