shell脚本编程经典实例-JP沃森
Linux Shell 学习笔记
第二章 标准输出
基础操作
- 去掉换行符
Terminal window printf "%s %s" next promptecho -n promptecho -e 'hi\c' # 不支持,\c 需配合 echo -e 使用(部分 shell 不兼容)
输出重定向
-
标准流编号
0
:标准输入 (STDIN)1
:标准输出 (STDOUT)2
:标准错误 (STDERR)
-
将输出和错误发送到不同文件
Terminal window myprogram > msg.out 2> msg.err -
将输出和错误发送到相同文件
Terminal window both >& outfile # 旧版语法both &> outfile # 推荐语法both > outfile 2>&1 # 兼容性语法 -
跳过文件标题
Terminal window tail -n +2 file # 显示除第一行外的所有行tail -n +1 file # 显示所有行 -
丢弃输出
Terminal window nohup > /dev/null 2>&1 # 注意:原文 "noiay" 应为 "nohup" -
保存多个命令的输出
Terminal window { pwd; ls; cd /tmp; ls; } > /tmp/all.out(pwd; ls; cd /tmp; ls) > /tmp/all.out -
输出作为输入,连接多个程序
Terminal window cat /etc/passwd | sort -
输出作为输入并保留副本
Terminal window cat my* | tr 'a-z' 'A-Z' | uniq | awk -f transform.awk | wccat my* | tr 'a-z' 'A-Z' | uniq | tee /tmp/out.1 | awk -f transform.awk | wc -
将错误一并重定向到 tee 文件
Terminal window find /etc '*.cnf' -print 2>&1 | tee /tmp/find.out -
以输出为参数连接两个程序
Terminal window rm $(find . -name '*.class') -
重定向失败时保存输出
Terminal window gcc bad.c 2> save.it # 屏幕不显示gcc bad.c 2>&1 | tee save.it # 屏幕显示 -
将输出发送到日志文件,错误发送到错误文件
Terminal window ./myscript 3>&1 1> out.log 2>&3- | tee -a err.log # -a 追加模式 -
避免意外覆盖文件
Terminal window set -o noclobber -
有意覆盖文件
Terminal window echo something > my.fileset -o noclobberecho some more >| my.filecat my.file
第三章 标准输入
从文件获取输入
wc < /etc/passwd
使用 Here Document
cat donors# donorsgrep -i $1 <<'EOF'pete $100joe $200bill $ 9EOF
./donors BILL
缩进(仅适用于制表符)
cat donors# donorsgrep -i $1 <<- 'EOF' pete $100 joe $200 bill $ 9 EOFls
获取用户输入
read -p "your name " ANSWERread -t 5 -p "your name " ANSWER # 5秒超时echo $ANSWER
获取 Yes/No 输入
function choice { CHOICE='' local prompt="$*" local answer read -p "$prompt" answer case "$answer" in [yY1] ) CHOICE='y' ;; [nN0] ) CHOICE='n' ;; * ) CHOICE="$answer" ;; esac}
choice "Do you want to look at the error logfile?[y/n]: "if [ "$CHOICE" != "n" ]; then less error.logfi
choice "Do you want to look at the message logfile?[y/n]: "if [ "$CHOICE" = "y" ]; then less message.logfi
选择选项列表
directorylist="Finished $(for i in /*; do [ -d "$i" ] && echo $i; done)"PS3='Directory to process? 'select directory in $directorylist; do if [ "$directory" == "Finished" ]; then echo "Finished processing directories." break elif [ -n "$directory" ]; then echo "You chose number $REPLY, processing $directory ..." break else echo "Invalid selection!" fidone
提升输入密码
read -s -p "password: " PASSWDprintf "%b\n"
第四章 执行命令
命令执行顺序
- 依次执行
Terminal window long; medium; short - 前一个成功后执行
Terminal window long && medium && short
同时执行多个命令
long & medium & short
检查命令是否成功
echo $? # 0 表示成功if (( $? )); then echo failed; else echo ok; fi
条件执行
if cd mytmp; then rm *; ficd mytmp && rm *
无人值守运行任务
nohup long &
出现故障时退出
cmd || { printf "%b\n" "Failed."; exit 1; }
执行变量中的命令
FN=/tmp/x.xPROG=echo$PROG $FNPROG=cat$PROG $FN
执行目录中的所有脚本
for SCRIPT in /path/to/scripts/*; do if [ -f "$SCRIPT" -a -x "$SCRIPT" ]; then $SCRIPT fidone
第五章 脚本编程基础:Shell 变量
变量操作
-
替换字符串
Terminal window NEWPATH=${PATH/:/ } # 替换第一次出现的冒号NEWPATH=${PATH//:/ } # 替换所有冒号 -
提高可读性
Terminal window [ -n "$results" ] && echo "Got a good $results" || echo 'Got an empty result' -
引用变量
Terminal window for FN in 1 2 3 4 5; dosomescript /tmp/rep${FN}port.txtdone -
导出变量
Terminal window export FNAME=/tmp/scratchexport SIZE=64 -
查看变量
Terminal window setenvexport -pdeclare -p
脚本参数
-
访问参数
Terminal window echo $1 $10 ${10} -
遍历参数
Terminal window for FN in "$@"; doecho changing $FNfile "$FN"done -
处理带空格的参数
Terminal window ls -l "${1}"touch /tmp/'oh the waste'./t.sh "oh the waste" -
统计参数数量
Terminal window if (( $# < 3 )); thenprintf "%b\n" "Error. Not enough arguments." >&2exit 1fi
字符串操作
-
子串操作
Terminal window name="number:123"echo ${name#*:} # 从冒号后开始截取echo ${name##*:} # 截取最后一个冒号后的内容echo ${name%:*} # 从右边删除第一个冒号及之后内容echo ${name%%:*} # 删除所有冒号及之后内容 -
替换字符串
Terminal window name="hello-world"echo ${name/hello/hi} # 替换第一次出现的 helloecho ${name//hello/hi} # 替换所有 hello -
文件路径操作
Terminal window MYIMAGEFILE=/tmp/img/img1.gifecho ${MYIMAGEFILE%/} # 删除结尾斜杠echo ${MYIMAGEFILE%/*} # 删除结尾斜杠及之后的内容echo ${MYIMAGEFILE##*/} # 获取文件名echo ${MYIMAGEFILE%.gif} # 删除后缀 -
数组操作
Terminal window MYVAR=(first second third home)echo runners on ${MYVAR[0]} and ${MYVAR[2]} -
大小写转换
Terminal window MYVAR="HELLO"echo ${MYVAR,,} # 全小写echo ${MYVAR^^} # 全大写 -
驼峰命名法
Terminal window while read TXT; doRA="${TXT,,}"RA2=($RA)echo ${RA2[@]^}done
第六章 Shell 逻辑与算术
算术操作
-
整数运算
Terminal window X=8; Y=9x=$((X+=5, Y*=3))echo $X $Y $x -
运算符
= 赋值 a=b*= 乘法 a*=b/= 除法 a/=b%= 求余 a%=b+= 加法 a+=b-= 减法 a-=b<<= 左移 a<<=b>>= 右移 a>>=b&= 与 a&=b^= 异或 a^=b|= 或 a|=b
条件分支
if [ -r $file -a -w $file ]; then echo "File is readable and writable"fi
循环
for ((i=0; i<10; i++)); do echo $idone
多路分支
case $FN in *.gif) gif2png "$FN" ;; *.png) pngOK "$FN" ;; *) echo "Unsupported file: $FN" ;;esac
批量操作
-
批量重命名
Terminal window for FN in *.jpg; do mv "$FN" "${FN%jpg}png"; done -
批量解压
Terminal window unzip '*.zip' -
搜索但不包含 grep 进程
Terminal window ps aux | grep '[s]sh' -
安全删除文件
Terminal window [ -n "$files_delete" ] && rm -rf "$files_delete"
测试脚本语法
bash -n t.sh