internal.html
来自「BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版」· HTML 代码 · 共 3,324 行 · 第 1/5 页
HTML
3,324 行
></TR></TABLE> </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX43"></A><P><B>例子 11-11. 展示<BCLASS="COMMAND">eval</B>命令的效果</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 y=`eval ls -l` # 与 y=`ls -l` 很相似 4 echo $y #+ 但是换行符将会被删除, 因为"echo"的变量未被""引用. 5 echo 6 echo "$y" # 用""将变量引用起来, 换行符就不会被空格替换了. 7 8 echo; echo 9 10 y=`eval df` # 与 y=`df` 很相似 11 echo $y #+ 换行符又被空格替换了. 12 13 # 当没有LF(换行符)出现时, 如果使用"awk"这样的工具来分析输出的结果, 14 #+ 应该能更容易一些. 15 16 echo 17 echo "===========================================================" 18 echo 19 20 # 现在,来看一下怎么用"eval"命令来"扩展"一个变量 . . . 21 22 for i in 1 2 3 4 5; do 23 eval value=$i 24 # value=$i 具有相同的效果, 在这里并不是非要使用"eval"不可. 25 # 一个缺乏特殊含义的变量将被评价为自身 -- 也就是说, 26 #+ 这个变量除了能够被扩展成自身所表示的字符外, 不能被扩展成任何其他的含义. 27 echo $value 28 done 29 30 echo 31 echo "---" 32 echo 33 34 for i in ls df; do 35 value=eval $i 36 # value=$i 在这里就与上边这句有了本质上的区别. 37 # "eval" 将会评价命令 "ls" 和 "df" . . . 38 # 术语 "ls" 和 "df" 就具有特殊含义, 39 #+ 因为它们被解释成命令, 40 #+ 而不是字符串本身. 41 echo $value 42 done 43 44 45 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="EX44"></A><P><B>例子 11-12. 强制登出(log-off)</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # 结束ppp进程来强制登出log-off. 3 4 # 本脚本应该以root用户的身份来运行. 5 6 killppp="eval kill -9 `ps ax | awk '/ppp/ { print $1 }'`" 7 # -------- ppp的进程ID ------- 8 9 $killppp # 这个变量现在成为了一个命令. 10 11 12 # 下边的命令必须以root用户的身份来运行. 13 14 chmod 666 /dev/ttyS3 # 恢复读写权限,否则什么? 15 # 因为在ppp上执行一个SIGKILL将会修改串口的权限, 16 #+ 我们把权限恢复到之前的状态. 17 18 rm /var/lock/LCK..ttyS3 # 删除串口琐文件.为什么? 19 20 exit 0 21 22 # 练习: 23 # ----- 24 # 1) 编写一个脚本来验证是否root用户正在运行它. 25 # 2) 做一个检查, 在杀掉某个进程之前, 26 #+ 检查一下这个将要被杀掉的进程是否正在运行. 27 # 3) 基于'fuser'来编写达到这个目的的另一个版本的脚本 28 #+ if [ fuser -s /dev/modem ]; then . . .</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="ROT14"></A><P><B>例子 11-13. 另一个<SPANCLASS="QUOTE">"rot13"</SPAN>版本</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # 使用'eval'的一个"rot13"的版本,(译者:rot13就是把26个字母,从中间分为2半,各13个). 3 # 与脚本"rot13.sh" 比较一下. 4 5 setvar_rot_13() # "rot13" 函数 6 { 7 local varname=$1 varvalue=$2 8 eval $varname='$(echo "$varvalue" | tr a-z n-za-m)' 9 } 10 11 12 setvar_rot_13 var "foobar" # 将 "foobar" 传递到 rot13函数中. 13 echo $var # sbbone 14 15 setvar_rot_13 var "$var" # 传递 "sbbone" 到rot13函数中. 16 # 又变成了原始值. 17 echo $var # foobar 18 19 # 这个例子是Segebart Chazelas编写的. 20 # 作者又修改了一下. 21 22 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>Rory Winston 捐献了下边的脚本, 关于使用<BCLASS="COMMAND">eval</B>命令. </P><DIVCLASS="EXAMPLE"><HR><ANAME="EVALEX"></A><P><B>例子 11-14. 在Perl脚本中使用<BCLASS="COMMAND">eval</B>命令来强制变量替换</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 In the Perl script "test.pl": 2 ... 3 my $WEBROOT = <WEBROOT_PATH>; 4 ... 5 6 To force variable substitution try: 7 $export WEBROOT_PATH=/usr/local/webroot 8 $sed 's/<WEBROOT_PATH>/$WEBROOT_PATH/' < test.pl > out 9 10 But this just gives: 11 my $WEBROOT = $WEBROOT_PATH; 12 13 However: 14 $export WEBROOT_PATH=/usr/local/webroot 15 $eval sed 's%\<WEBROOT_PATH\>%$WEBROOT_PATH%' < test.pl > out 16 # ==== 17 18 That works fine, and gives the expected substitution: 19 my $WEBROOT = /usr/local/webroot; 20 21 22 ### Paulo Marcel Coelho Aragao校正了这个原始例子.</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="CAUTION"><P></P><TABLECLASS="CAUTION"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/caution.gif"HSPACE="5"ALT="Caution"></TD><TDALIGN="LEFT"VALIGN="TOP"><P><BCLASS="COMMAND">eval</B>命令是有风险的, 如果你有更合适的方法来实现功能的话, 尽量避免使用它. <KBDCLASS="USERINPUT">eval $COMMANDS</KBD>将会执行命令<TTCLASS="REPLACEABLE"><I>COMMANDS</I></TT>的内容, 如果命令中包含有<BCLASS="COMMAND">rm -rf *</B>这样的东西, 可能就不是你想要的了. 当你运行一个包含有<BCLASS="COMMAND">eval</B>命令的陌生人所编写的代码片段的时候, 这是一件很危险的事情. </P></TD></TR></TABLE></DIV></DD><DT><ANAME="SETREF"></A><BCLASS="COMMAND">set</B></DT><DD><P><BCLASS="COMMAND">set</B>命令用来修改内部脚本变量的值. 它的一个作用就是触发<AHREF="options.html#OPTIONSREF">选项标志位</A>来帮助决定脚本的行为. 另一个作用是以一个命令的结果(<KBDCLASS="USERINPUT">set `command`</KBD>)来重新设置脚本的<AHREF="internalvariables.html#POSPARAMREF">位置参数</A>. 脚本将会从命令的输出中重新分析出位置参数. </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX34"></A><P><B>例子 11-15. 使用<BCLASS="COMMAND">set</B>命令来改变脚本的位置参数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 # script "set-test" 4 5 # 使用3个命令行参数来调用这个脚本, 6 # 比如, "./set-test one two three". 7 8 echo 9 echo "Positional parameters before set \`uname -a\` :" 10 echo "Command-line argument #1 = $1" 11 echo "Command-line argument #2 = $2" 12 echo "Command-line argument #3 = $3" 13 14 15 set `uname -a` # 把`uname -a`的命令输出设置 16 # 为新的位置参数. 17 18 echo $_ # unknown(译者注: 这要看你的uname -a输出了,这句打印出的就是输出的最后一个单词.) 19 # 在脚本中设置标志. 20 21 echo "Positional parameters after set \`uname -a\` :" 22 # $1, $2, $3, 等等. 这些位置参数将被重新初始化为`uname -a`的结果 23 echo "Field #1 of 'uname -a' = $1" 24 echo "Field #2 of 'uname -a' = $2" 25 echo "Field #3 of 'uname -a' = $3" 26 echo --- 27 echo $_ # --- 28 echo 29 30 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>关于位置参数更多有趣的事情.</P><DIVCLASS="EXAMPLE"><HR><ANAME="REVPOSPARAMS"></A><P><B>例子 11-16. 反转位置参数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # revposparams.sh: 反转位置参数. 3 # 本脚本由Dan Jacobson所编写, 本书作者做了一些格式上的修正. 4 5 6 set a\ b c d\ e; 7 # ^ ^ 转义的空格 8 # ^ ^ 未转义的空格 9 OIFS=$IFS; IFS=:; 10 # ^ 保存旧的IFS, 然后设置新的IFS. 11 12 echo 13 14 until [ $# -eq 0 ] 15 do # 步进位置参数. 16 echo "### k0 = "$k"" # 步进之前 17 k=$1:$k; # 将每个位置参数都附加在循环变量的后边. 18 # ^ 19 echo "### k = "$k"" # 步进之后 20 echo 21 shift; 22 done 23 24 set $k # 设置一个新的位置参数. 25 echo - 26 echo $# # 察看位置参数的个数. 27 echo - 28 echo 29 30 for i # 省略 "in list" 结构, 31 #+ 为位置参数设置变量 -- i --. 32 do 33 echo $i # 显示新的位置参数. 34 done 35 36 IFS=$OIFS # 恢复 IFS. 37 38 # 问题: 39 # 是否有必要设置新的IFS, 内部域分隔符, 40 #+ 才能够让这个脚本正常运行? (译者注: 当然有必要.) 41 # 如果你没设置新的IFS, 会发生什么? 试一下. 42 # 并且, 在第17行, 为什么新的IFS要使用 -- 一个冒号 -- , 43 #+ 来将位置参数附加到循环变量中? 44 # 这么做的目的是什么? 45 46 exit 0 47 48 $ ./revposparams.sh 49 50 ### k0 = 51 ### k = a b 52 53 ### k0 = a b 54 ### k = c a b 55 56 ### k0 = c a b 57 ### k = d e c a b 58 59 - 60 3 61 - 62 63 d e 64 c 65 a b</PRE></FONT></TD></TR></TABLE><HR></DIV><P>不使用任何选项或参数来调用<BCLASS="COMMAND">set</B>命令的话, 将会列出所有的<AHREF="othertypesv.html#ENVREF">环境变量</A>和其他所有的已经初始化过的变量. <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">set</KBD><SAMPCLASS="COMPUTEROUTPUT">AUTHORCOPY=/home/bozo/posts BASH=/bin/bash BASH_VERSION=$'2.05.8(1)-release' ... XAUTHORITY=/home/bozo/.Xauthority _=/etc/bashrc variable22=abc variable23=xzy</SAMP> </PRE></FONT></TD></TR></TABLE> </P><P>如果使用参数<CODECLASS="OPTION">--</CODE>来调用<BCLASS="COMMAND">set</B>命令的话, 将会明确的分配位置参数. 如果<CODECLASS="OPTION">--</CODE>选项后边没有跟变量名的话, 那么结果就使得所有位置参数都被<EM>unsets</EM>了. </P><DIVCLASS="EXAMPLE"><HR><ANAME="SETPOS"></A><P><B>例子 11-17. 重新分配位置参数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 variable="one two three four five" 4 5 set -- $variable 6 # 将位置参数的内容设为变量"$variable"的内容. 7 8 first_param=$1 9 second_param=$2 10 shift; shift # 将最前面的两个位置参数移除. 11 remaining_params="$*" 12 13 echo 14 echo "first parameter = $first_param" # one 15 echo "second parameter = $second_param" # two 16 echo "remaining parameters = $remaining_params" # three four five 17 18 echo; echo 19 20 # 再来一次. 21 set -- $variable 22 first_param=$1 23 second_param=$2 24 echo "first parameter = $first_param" # one 25 echo "second parameter = $second_param" # two 26 27 # ====================================================== 28 29 set -- 30 # 如果没指定变量,那么将会unset所有的位置参数. 31 32 first_param=$1 33 second_param=$2 34 echo "first parameter = $first_param" # (null value) 35 echo "second parameter = $second_param" # (null value) 36 37 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>参考<AHREF="loops1.html#EX22A">例子 10-2</A>和<AHREF="extmisc.html#EX33A">例子 12-51</A>.</P></DD><DT><ANAME="UNSETREF"></A><BCLASS="COMMAND">unset</B></DT><DD><P><BCLASS="COMMAND">unset</B>命令用来删除一个shell变量, 这个命令的效果就是把这个变量设为<EM>null</EM>. 注意: 这个命令对位置参数无效. </P><P> <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">unset PATH</KBD><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo $PATH</KBD><SAMPCLASS="COMPUTEROUTPUT"> </SAMP><SAMPCLASS="PROMPT">bash$ </SAMP></PRE></FONT></TD></TR></TABLE> </P><DIVCLASS="EXAMPLE"><HR><ANAME="UNS"></A><P><B>例子 11-18. <SPANCLASS="QUOTE">"Unsett"</SPAN>一个变量</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?