Linux Shell 脚本攻略(一)

虽然用Linux好几年了,但是对shell脚本的掌握基本为零……最近需要做一些文件批量重命名,图像批量预处理,文本批量预处理的琐碎而重复的工作,于是乎下定决心好好学习一下shell脚本。于是找了一本口碑不错的shell脚本入门书—-《Linux Shell 脚本攻略 第2版》,是印度人Shantanu Tushar和Sarath Lakshman写的。边看边写博客系列(计划分九个系列完成)当做读书笔记,同时,也不完全是读书笔记,会加上一些解释的链接或者个人的经验:)当然,如果有人看,也算是做个“脱水版”的精炼shell脚本入门“指南”吧:)

  1. 基本的文件格式结构,运行规则:文件开头第一行 #!/bin/bash(这里可以是别的shell的路径),#!这玩意叫shebang,运行可以$ bash script.sh 这种运行方式首行的shebang就没什么用了,或者$ chmod +x script.sh 然后 $ ./script.sh。
  2. 命令间隔符:换行符或者分号; 是等价的,也就是说 $ cmd1; cmd2 等同于 $ cmd1 $ cmd2。
  3. 终端的打印:最基本的echo,$ echo “Hello world”,注意这里也可以用单引号,但是有些差别,关于单双引号的不同,后面再说,简单的来讲就是单引号不拓展特殊符号(也就是原样输出)。高级一点的printf,这个大家都熟悉,和C里的函数用法差不多,一个小例子:$ printf “%-5s %-10s %-4s\n” No Name Mark,几点注意的地方,1. %s, %c, %d, %f和C语言的含义相同,“-”号表示左对齐,“-”号后面跟的数字表示字符宽度。更多的printf用法随意搜索便有很详细的解释。2. 需要加\n手动换行,echo就不需要。3. 双引号内设置格式,需要打印的内容在引号外面。
  4. echo打印转义字符:加上“-e”参数,例如,$ echo -e “\t” ,bonus:echo打印彩色,看起来很炫酷的样子,$ echo -e “\e[1;31m THIS IS RED TEXT \e[0m”, \e[1;31 将颜色设置为红色,\e[0m 又把颜色重置了,更多的颜色以及解释请看 这个链接
  5. 环境变量:查看某个运行程序的环境变量 $ cat /proc/$PID/environ,其中$PID的获取用pgrep命令,例如:$ pgrep gedit,输出一大堆,而且居然还没有换行,因为这些字符是name=value的形式显示,\0也就是null结尾,我们可以吧\0换成\n,$ cat /proc/$PID/environ | tr ‘\0’ ‘\n’,这里用到了管道以及tr命令,详细的用法后面会解释。
  6. 变量的赋值与取值:赋值:var=value,注意等号左右没有空格,有空格就是相等的意思了。取值:$var或者${var},加花括号是为了区分,例如${var}s,如果不加花括号,则会去取vars的值,然而这个变量不存在也就是为空。bonus:1. 获得字符串长度:length=${#var}。2. 识别当前的shell:echo $SHELL,或者echo $0(试试看这两个有什么不同?)。 3.检查执行当前脚本的用户是否为超级用户:检查$UID是否为0,关于如何检查是否相等,后面会提及。4.修改BASH的提示符:设置PS1变量,例如:PS1=”PROMPT>”,当然,也可以用前面炫酷的彩色效果,这里还有些小技巧,比如:\u是用户名等等。详细的内容可以查询搜索引擎。
  7. 环境变量的设置:环境变量也是变量,但是是一些名称约定俗成的变量,例如HOME,PATH等等,详情请见这里
  8. 在shell中进行数学运算:shell中var=value赋值后存储的是字符串,可以使用let进行运算,例如:no1=4; no2=5; let result=no1+no2; echo $result,自加/自减:let no1++/–,简写:let no+=6也就是let no=no+6。let可以换成[ ]或者(( )),用这两个符合,变量名前面可加可不加$,例如:result=$[ no1 + no2 ],注意两侧的空格。同时,expr也可以,例如:result=$(expr $no1 + $no2 )。以上方法适用于整数运算,浮点数需要借助bc。bc有很多选项,这里举几个例子:1. 基本运算:echo “4 * 0.56” | bc。2. 设定小数点精度echo “scale=2;4 * 0.56” | bc。3. 进制转换:echo “obase=2;ibase=10;53” | bc。4. 调用数学函数:echo “sqrt(100)” | bc。
  9. 文件描述符以及重定向:0:stdin,1:stdout,2:stderr,重定向:>覆盖模式,>>追加模式,例如:echo “Hello world” >/>> text.txt。stderr重定向:2>,例如$ ls + 2> err.txt。多个重定向:$ cmd 2>stderr.txt 1>stdout.txt。stderr转换成stdout,与stdout同时重定向:$ cmd 2>&1 output.txt。重定向到/dev/null的所有信息都会像进入黑洞一样被抛弃。三通tee命令,可以把tee看成一个三通管道,左边的口进来,copy一份往下送,右边口原样输出。例如:ls | tee out.txt | cat -n。exec自定义文件描述符:exec 3\<input.txt,\<表示读取,>表示写入,现在3就可以作为文件描述符使用了。同样的,>>表示追加写入。注意,文件描述符是”一次性使用的“,每次使用都要用exec重新分配。
  10. 数组与关联数组(BASH从4.0才开始支持关联数组,请检查BASH版本:bash –version):赋值:array_var=(1 2 3 4 5),或者array_var[0]=”test1″。打印:echo ${array_var[0]}。打印全部:echo ${array_var[*]}或者echo ${array_var[@]},打印数组长度:echo ${#array_var[*]}。关联数组:使用任意文本作为数组的索引。首先declare -A ass_array,赋值:ass_array[index1]=”test1″。其他用法同数组。打印索引列表:echo ${!ass_array[*]}
  11. 命令别名:alias new_command=’old command’,若不希望执行命令别名,仅仅希望执行命令本身,可以用\转义。例如:alias cat=’ls’,执行cat则会输出ls的结果,这时,想要执行cat应该是\cat。
  12. 获取终端信息:获取终端的行数,列数:tput lines,tput cols。获取当前终端名:tput longname。详细的tput用法请见这篇文章
  13. 获取、设置时间与延时:首先,介绍一个概念:Unix时间。读取日期:date。读取Unix时间:date +%s。日期格式化:date –date “Wed Mar 22 22:21:13 CST 2017” +%s,其中s可以换成不同的符号输出不同的日期格式。具体请查看man date的FORMAT部分。设置日期:需要root权限,date -s “日期”。延时:sleep sec,其中sec是需要延时的秒数。
  14. 调试脚本:$ bash -x script.sh,如果仅仅想对部分语句调试,在语句的前后分别加上set -x和set +x即可。
  15. 函数:定义函数:fname() { statements; }。函数调用与参数传递:fname arg1 arg2; 访问参数:$1是第一个参数,$n是第n个参数,$@以列表方式一次性打印所有参数。注:BASH的函数支持递归调用。
  16. 检测命令的返回状态:$ echo $?返回上条命令的返回状态,一般来讲,非0值表示异常退出。
  17. 管道:Linux的基本设计思想之一就是,每个程序小而精,只干且干好一件事情,这样很多小工具组合起来就非常强大且稳健。管道是这些小工具能够联合工作的重要基础之一。cmd1 | cmd2 | cmd3表示cmd1加工输入后输出给cmd2,cmd2加工cmd1的输出后输出给cmd3。
  18. 反引用:` commd ` 可以看成执行``之间的命令,例如output=`ls`; echo $output
  19. 子shell:将命令用()括起来代表命令在子shell中执行,此时命令不会影响主shell。例如pwd; (cd /bin; ls); pwd;,虽然cd到了/bin但是主shell的工作目录并不会改变。
  20. read的使用:read -s var:无回显,read -p “Enter your input: ” var,带提示信息,read -t timeout var,特定时限内读入,read -d delim var,以delim为输入行的结束。
  21. 内部字符分隔符(Internal Field Separator,IFS):简单地说,就是通过IFS这个环境变量告诉shell如何分割字符。直接看例子:data=”name,sex,location”; oldIFS=$IFS; for item in $data; do echo $item; done IFS=$oldIFS。
  22. 循环:for循环:for var in list; do commd; done; C语言风格:for ((i=0;i\<10;i++)){ commd; }。while循环:while condition; do commd; done; until循环:until condition; do commd; done;
  23. 比较与测试:if、else:if condition; then commd; else if condition; then commd; else commd; fi。[ condition ] && action:如果condition为真则执行action,[ condition ] || action:如果condition为假则执行action。注意[ ]周围的空格。算数比较:[ $var -eq/ne/gt/lt/ge/le 0 ],如果var等于/不等于/大于/小于/大于等于/小于等于0,则返回真。辅助记忆:eq是equal也就是相等,ne是non equal也就是不相等,g是greater也就是大于,l是less也就是小于。-a是与-o是或(and和or),例如:[ $var1 -ne 0 -a $var2 -gt 2 ]表示如果var1不等于0并且var2大于2则返回真。文件系统相关测试:[ -f/x/d/e/c/b/w/r/L $var ],如果给定的变量包含正常的文件路径或文件名/可执行/是目录/存在/是字符设备文件/是块设备文件/可写/可读/是符号链接,则返回真。辅助记忆,file/execute/dir/exist/char/block/write/read/link。字符串比较:使用双中括号。[[ $str1 ==/!=/>/< $str2 ]],如果str1等于/不等于/字典序大于/字典序小于str2,则返回真。[[ -z/n $str1 ]],若str1包含的是空/非空字符串,则返回真。辅助记忆:zero/non-zero。对于字符串,同样逻辑运算符&&与||也适用。test命令:test可以避免使用过多括号,与前面的命令相同,例如:[ $var -eq 0 ]等价于test $var -eq 0。

Leave a Reply

Your email address will not be published. Required fields are marked *