Shell技巧小结~

来源:互联网 发布:一键部署java环境 编辑:程序博客网 时间:2024/06/07 19:58

Shell脚本作为shell命令批处理执行的实现形式,其语法和功能是随着需求逐步添加并完善的,因此不同于我们熟知的C或是JAVA从设计之初就尽可能考虑到日后各种使用场景,Shell脚本的功能设计更像是堆积木一样在长期的演进中变成今天这个样子,为了灵活的在脚本和C-Like编程语言间自由转变,有必要对两者的设计理念以及功能机制进行剖析,这里仅对shell的特性进行简要的分析和总结。

1.shell的设计中并没有数字的概念,一般情况下数字也是以字符串的形式存在的,因此在shell中实现数字运算要使用let命令或者j=$(($j + 1))的形式。

2.本质上讲shell脚本就是shell命令的集合,shell命令作为shell的子进程执行并在终端上返回数据,在shell的设计中,变量的数据结构特别简单,或者说shell变量就是数组,如果将cat命令或者$(cmd)命令(或反引号)的执行结果赋值到变量中,shell会自动以空格和换行符为分隔符将数据分割为以单空格分隔的字符串组,并记录到变量中,因此如果使用str=$(ls -al)记录ls -al执行结果,echo $str将是一串让人头疼的字符串组。在需要保留命令执行结果的时候可以使用管道将结果输出到临时log文件中,并使用sed等命令进行字符处理。

#!/bin/bashDBUSER=xxDBPW=yyDBHOST=zzDBPORT=kkDBTABLE=uumsql(){if [ $1 == "-h" ]; thencat <<hcommand usage:    msql -h | provide help info   msql -s "sql1; sql2; ..." | echo data without board   mysql "sql1; sql2; ..." | echo data with boardhelif [ $1 == "-s" ]; thenread QUERY <<< $(echo $@ | sed 's/\-s //g' | sed "s/'NULL'/NULL/g");echo $QUERY | mysql --user=$DBUSER --password=$DBPW --host $DBHOST --port $DBPORT $DBTABLE;elseread QUERY <<< $(echo $* | sed "s/'NULL'/NULL/g");#echo $QUERY;mysql --user=$DBUSER --password=$DBPW --host $DBHOST --port $DBPORT $DBTABLE -e "$QUERY";fi}msql $@

3.上述shell变量的特性并不是一无是处,因此shell变量本质上就是数组,因此可以使用for i in $var来遍历变量(字符串组)中的字符串,更进一步可以使用for i in $(cat xx.log)来遍历文件各行均没有空格的文本文件行,如果文件行有空格会依照shell的解析原则该行会被作为多个字符串被遍历。

4.shell脚本参数和函数参数解析原则一样都是将脚本/函数后的数据以空格/换行符为分隔符解析为单空格分隔的字符串组并按照先后顺序被赋值到对应的$n中,也可以使用$@/$*调用整个字符串组。shell中被双引号括住的字符串组并不意味着它们是一个字符串,shell仍然会按照空格/换行符进行字符串组解析,双引号的作用仅仅在于可以实现转义,test "this is a" world中脚本仍然会获得4个参数变量。使用shift命令实现对参数数组的堆栈操作,通常配合case语法用来解析参数列表。

#!/bin/bashhelpinfo(){cat <<EOFUsage:  -a "v1" | Var1=v1  -b "v2" | Var2=v2  -c | Var3=17  -h | echo help infoEOF}while [ "$1" ]; docase $1 in-a)  Var1=$2; shift;;-b)  Var2=$2; shift;;-c)  Var3=17;;-h)  helpinfo;;esacshiftdone[ "$Var1" ] && echo "Var1: $Var1"[ "$Var2" ] && echo "Var2: $Var2"[ "$Var3" ] && echo "Var3: $Var3"

5.&&和||可以用来简化判断语句的使用。可以使用$?调用上一个子进程执行与否,执行成功$?将置0,失败一般置1,该参数也可以由上一个函数使用return返回值赋值。

#!/bin/bashpingl(){ping -c 1 $IPR && {echoc "RRU IP is reachable!"return 0} || {echoc "waitting to reach RRU IP~"return 1}loop=$(($loop + 1))[[ $loop == 300 ]] && return 0}while true; do pingl[ $? == 0 ] && break done

6.在shell命令中可以使用&符号将子进程放置后台,这也意味着shell主进程不在wait子进程的执行情况,直接执行下一个子进程,cmd &因此在脚本中可以实现多进程执行命令:

for ip in `grep "==>" /bin/ipsearch | grep -v null | awk '/==>/{ print $1 }'`do(export downfile=/tmp/${ip}.tmpping_ip $ip)&done

当然也可以使用(cmd &)将子进程被int进程收管变成daemon进程。参考http://blog.csdn.net/fyh2003/article/details/46880021

7.Shell中有三个默认的文件操作符,分别是标准输入(0),标准输出(1)和错误输出(2),对于任何Shell命令,Shell会自动绑定三个文件描述符,标准输入绑定为键盘,标准输出和错误输出都是屏幕,可以使用输入输出操作符重定向默认的输入输出,一般格式为command >/>>/<

'>log' == '1>log''2>log 1>log' == '>log 2>&1' == '&>log''>>log' == '| tee log' 

8.Shell可以使用( )和{ }定义代码块,既一连串的command,二者的区别在于( )里的命令是由子shell派生执行的,而{ }的命令还是在当前shell派生执行的(这也可以解释(command &)会使命令进程被init 进程托管,因为命令进程是子shell派生的子子进程,而且&后台符号使子进程不在wait命令进程的执行情况,在没有其他命令的情况下子shell进程直接结束,导致命令进程成为孤儿进程进而被init进程托管),除此之外:
①( )和{ }里的命令都使用分号;隔开,但( )最后一个命令不用加分号,而{ }最后一个命令必须加分号;或者每个命令占据一行。
②{ }里的第一个命令必须和{有一个空格,而( )不需要。

 (var=notest; echo $var) { var=notest; echo $var;}

③( )和{ }里某个命令的重定向只影响该命令,但符号外的重定向影响所有的命令

{ var1=test1;var2=test2;echo $var1>a;echo $var2;}(     echo "1"     echo "2" ) | awk '{print NR,$0}'

9.使用exit可以在脚本任意处(包括函数内)退出脚本,想要实现函数级别的退出可在函数内使用return语句。

10.每个shell脚本都由当前shell派生的子shell进程执行的,所以可以在脚本中定义更改环境变量(setenvexportunset, etc),更改的环境变量仅在子shell及其派生子shell中有效,并不影响当前shell。

0 0
原创粉丝点击