internalvariables.html
来自「BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版」· HTML 代码 · 共 3,354 行 · 第 1/4 页
HTML
3,354 行
COLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 E_WRONG_DIRECTORY=73 4 5 clear # 清屏. 6 7 TargetDirectory=/home/bozo/projects/GreatAmericanNovel 8 9 cd $TargetDirectory 10 echo "Deleting stale files in $TargetDirectory." 11 12 if [ "$PWD" != "$TargetDirectory" ] 13 then # 防止偶然删错目录. 14 echo "Wrong directory!" 15 echo "In $PWD, rather than $TargetDirectory!" 16 echo "Bailing out!" 17 exit $E_WRONG_DIRECTORY 18 fi 19 20 rm -rf * 21 rm .[A-Za-z0-9]* # 删除点文件(译者注: 隐藏文件). 22 # rm -f .[^.]* ..?* 为了删除以多个点开头的文件. 23 # (shopt -s dotglob; rm -f *) 也可以. 24 # 感谢, S.C. 指出这点. 25 26 # 文件名可以包含ascii中0 - 255范围内的所有字符, 除了"/". 27 # 删除以各种诡异字符开头的文件将会作为一个练习留给大家. 28 29 # 如果必要的话, 这里预留给其他操作. 30 31 echo 32 echo "Done." 33 echo "Old files deleted in $TargetDirectory." 34 echo 35 36 37 exit 0</PRE></FONT></TD></TR></TABLE></P></DD><DT><ANAME="REPLYREF"></A><CODECLASS="VARNAME">$REPLY</CODE></DT><DD><P>当没有参数变量提供给<AHREF="internal.html#READREF">read</A>命令的时候, 这个变量会作为默认变量提供给read命令. 也可以用于<AHREF="testbranch.html#SELECTREF">select</A>菜单, 但是只提供所选择变量的编号, 而不是变量本身的值. </P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # reply.sh 3 4 # REPLY是提供给'read'命令的默认变量. 5 6 echo 7 echo -n "What is your favorite vegetable? " 8 read 9 10 echo "Your favorite vegetable is $REPLY." 11 # 当且仅当没有变量提供给"read"命令时, 12 #+ REPLY才保存最后一个"read"命令读入的值. 13 14 echo 15 echo -n "What is your favorite fruit? " 16 read fruit 17 echo "Your favorite fruit is $fruit." 18 echo "but..." 19 echo "Value of \$REPLY is still $REPLY." 20 # $REPLY还是保存着上一个read命令的值, 21 #+ 因为变量$fruit被传入到了这个新的"read"命令中. 22 23 echo 24 25 exit 0</PRE></FONT></TD></TR></TABLE></P></DD><DT><CODECLASS="VARNAME">$SECONDS</CODE></DT><DD><P>这个脚本已经运行的时间(以秒为单位).</P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 3 TIME_LIMIT=10 4 INTERVAL=1 5 6 echo 7 echo "Hit Control-C to exit before $TIME_LIMIT seconds." 8 echo 9 10 while [ "$SECONDS" -le "$TIME_LIMIT" ] 11 do 12 if [ "$SECONDS" -eq 1 ] 13 then 14 units=second 15 else 16 units=seconds 17 fi 18 19 echo "This script has been running $SECONDS $units." 20 # 在一台比较慢或者是附载过大的机器上, 21 #+ 在单次循环中, 脚本可能会忽略计数. 22 sleep $INTERVAL 23 done 24 25 echo -e "\a" # Beep!(哔哔声!) 26 27 exit 0</PRE></FONT></TD></TR></TABLE></P></DD><DT><CODECLASS="VARNAME">$SHELLOPTS</CODE></DT><DD><P>shell中已经激活的<AHREF="options.html#OPTIONSREF">选项</A>的列表, 这是一个只读变量. <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo $SHELLOPTS</KBD><SAMPCLASS="COMPUTEROUTPUT">braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs</SAMP> </PRE></FONT></TD></TR></TABLE> </P></DD><DT><CODECLASS="VARNAME">$SHLVL</CODE></DT><DD><P>Shell级别, 就是Bash被嵌套的深度. 如果是在命令行中, 那么$SHLVL为1, 如果在脚本中那么$SHLVL为2. </P></DD><DT><CODECLASS="VARNAME">$TMOUT</CODE></DT><DD><P>如果<TTCLASS="REPLACEABLE"><I>$TMOUT</I></TT>环境变量被设置为非零值<EM>time</EM>的话, 那么经过<EM>time</EM>秒后, shell提示符将会超时. 这将会导致登出(logout).</P><P>在2.05b版本的Bash中, <TTCLASS="REPLACEABLE"><I>$TMOUT</I></TT>变量与命令<AHREF="internal.html#READREF">read</A>可以在脚本中结合使用.</P><P> <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 # 只能够在Bash脚本中使用, 必须使用2.05b或之后版本的Bash. 2 3 TMOUT=3 # 提示输入时间为3秒. 4 5 echo "What is your favorite song?" 6 echo "Quickly now, you only have $TMOUT seconds to answer!" 7 read song 8 9 if [ -z "$song" ] 10 then 11 song="(no answer)" 12 # 默认响应. 13 fi 14 15 echo "Your favorite song is $song."</PRE></FONT></TD></TR></TABLE> </P><P>还有更加复杂的办法可以在脚本中实现定时输入. 一种办法就是建立一个定式循环, 当超时的时候给脚本发个信号. 不过这也需要有一个信号处理例程能够捕捉(参见<AHREF="debugging.html#EX76">例子 29-5</A>)由定时循环所产生的中断. (哇欧!).</P><DIVCLASS="EXAMPLE"><HR><ANAME="TMDIN"></A><P><B>例子 9-2. 定时输入</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # timed-input.sh 3 4 # TMOUT=3 在新一些的Bash版本上也能运行的很好. 5 6 7 TIMELIMIT=3 # 这个例子中设置的是3秒. 也可以设置为其他的时间值. 8 9 PrintAnswer() 10 { 11 if [ "$answer" = TIMEOUT ] 12 then 13 echo $answer 14 else # 别和上边的例子弄混了. 15 echo "Your favorite veggie is $answer" 16 kill $! # 不再需要后台运行的TimerOn函数了, kill了吧. 17 # $! 变量是上一个在后台运行的作业的PID. 18 fi 19 20 } 21 22 23 24 TimerOn() 25 { 26 sleep $TIMELIMIT && kill -s 14 $$ & 27 # 等待3秒, 然后给脚本发送一个信号. 28 } 29 30 Int14Vector() 31 { 32 answer="TIMEOUT" 33 PrintAnswer 34 exit 14 35 } 36 37 trap Int14Vector 14 # 定时中断(14)会暗中给定时间限制. 38 39 echo "What is your favorite vegetable " 40 TimerOn 41 read answer 42 PrintAnswer 43 44 45 # 无可否认, 这是一个定时输入的复杂实现, 46 #+ 然而"read"命令的"-t"选项可以简化这个任务. 47 # 参考后边的"t-out.sh". 48 49 # 如果你需要一个真正优雅的写法... 50 #+ 建议你使用C或C++来重写这个应用, 51 #+ 你可以使用合适的函数库, 比如'alarm'和'setitimer'来完成这个任务. 52 53 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>另一种选择是使用<AHREF="system.html#STTYREF">stty</A>.</P><DIVCLASS="EXAMPLE"><HR><ANAME="TIMEOUT"></A><P><B>例子 9-3. 再来一个, 定时输入</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # timeout.sh 3 4 # 由Stephane Chazelas所编写, 5 #+ 本书作者做了一些修改. 6 7 INTERVAL=5 # 超时间隔 8 9 timedout_read() { 10 timeout=$1 11 varname=$2 12 old_tty_settings=`stty -g` 13 stty -icanon min 0 time ${timeout}0 14 eval read $varname # 或者仅仅读取$varname变量 15 stty "$old_tty_settings" 16 # 参考"stty"的man页. 17 } 18 19 echo; echo -n "What's your name? Quick! " 20 timedout_read $INTERVAL your_name 21 22 # 这种方法可能并不是在每种终端类型上都可以正常使用的. 23 # 最大的超时时间依赖于具体的中断类型. 24 #+ (通常是25.5秒). 25 26 echo 27 28 if [ ! -z "$your_name" ] # 如果在超时之前名字被键入... 29 then 30 echo "Your name is $your_name." 31 else 32 echo "Timed out." 33 fi 34 35 echo 36 37 # 这个脚本的行为可能与脚本"timed-input.sh"的行为有些不同. 38 # 每次按键, 计时器都会重置(译者注: 就是从0开始). 39 40 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><P>可能最简单的办法就是使用<CODECLASS="OPTION">-t</CODE>选项来<AHREF="internal.html#READREF">read</A>了.</P><DIVCLASS="EXAMPLE"><HR><ANAME="TOUT"></A><P><B>例子 9-4. 定时<BCLASS="COMMAND">read</B></B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # t-out.sh 3 # 从"syngin seven"的建议中得到的灵感 (感谢). 4 5 6 TIMELIMIT=4 # 4秒 7 8 read -t $TIMELIMIT variable <&1 9 # ^^^ 10 # 在这个例子中, 对于Bash 1.x和2.x就需要"<&1"了, 11 # 但是Bash 3.x就不需要. 12 13 echo 14 15 if [ -z "$variable" ] # 值为null? 16 then 17 echo "Timed out, variable still unset." 18 else 19 echo "variable = $variable" 20 fi 21 22 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV></DD><DT><ANAME="UIDREF"></A><CODECLASS="VARNAME">$UID</CODE></DT><DD><P>用户ID号</P><P>当前用户的用户标识号, 记录在<TTCLASS="FILENAME">/etc/passwd</TT>文件中 </P><P>这是当前用户的真实id, 即使只是通过使用<AHREF="system.html#SUREF">su</A>命令来临时改变为另一个用户标识, 这个id也不会被改变. <CODECLASS="VARNAME">$UID</CODE>是一个只读变量, 不能在命令行或者脚本中修改它, 并且和<AHREF="system.html#IDREF">id</A>内建命令很相像.</P><DIVCLASS="EXAMPLE"><HR><ANAME="AMIROOT"></A><P><B>例子 9-5. 我是root么?</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # am-i-root.sh: 我是不是root用户? 3 4 ROOT_UID=0 # Root的$UID为0. 5 6 if [ "$UID" -eq "$ROOT_UID" ] # 只有真正的"root"才能经受得住考验? 7 then 8 echo "You are root." 9 else 10 echo "You are just an ordinary user (but mom loves you just the same)." 11 fi 12 13 exit 0 14 15 16 # ============================================= # 17 # 下边的代码不会执行, 因为脚本在上边已经退出了. 18 19 # 下边是另外一种判断root用户的方法: 20 21 ROOTUSER_NAME=root 22 23 username=`id -nu` # 或者... username=`whoami` 24 if [ "$username" = "$ROOTUSER_NAME" ] 25 then 26 echo "Rooty, toot, toot. You are root." 27 else 28 echo "You are just a regular fella." 29 fi</PRE></FONT></TD></TR></TABLE><HR></DIV><P>也请参考一下<AHREF="sha-bang.html#EX2">例子 2-3</A>.</P><DIVCLASS="NOTE"><P></P><TABLECLASS="NOTE"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/note.gif"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>变量<CODECLASS="VARNAME">$ENV</CODE>, <CODECLASS="VARNAME">$LOGNAME</CODE>, <CODECLASS="VARNAME">$MAIL</CODE>, <CODECLASS="VARNAME">$TERM</CODE>, <CODECLASS="VARNAME">$USER</CODE>, 和<CODECLASS="VARNAME">$USERNAME</CODE>都<EM>不是</EM>Bash的<AHREF="internal.html#BUILTINREF">内建</A>变量. 然而这些变量经常在Bash的<AHREF="files.html#FILESREF1">启动文件</A>中被当作<AHREF="othertypesv.html#ENVREF">环境变量</A>来设置. <ANAME="SHELLVARREF"></A><CODECLASS="VARNAME">$SHELL</CODE>是用户登陆shell的名字, 它可以在<TTCLASS="FILENAME">/etc/passwd</TT>中设置, 或者也可以在<SPANCLASS="QUOTE">"init"</SPAN>脚本中设置, 并且它也不是Bash内建的.</P><P> <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">tcsh% </SAMP><KBDCLASS="USERINPUT">echo $LOGNAME</KBD><SAMPCLASS="COMPUTEROUTPUT">bozo</SAMP><SAMPCLASS="PROMPT">tcsh% </SAMP><KBDCLASS="USERINPUT">echo $SHELL</KBD><SAMPCLASS="COMPUTEROUTPUT">/bin/tcsh</SAMP><SAMPCLASS="PROMPT">tcsh% </SAMP><KBDCLASS="USERINPUT">echo $TERM</KBD><SAMPCLASS="COMPUTEROUTPUT">rxvt</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo $LOGNAME</KBD><SAMPCLASS="COMPUTEROUTPUT">bozo</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo $SHELL</KBD><SAMPCLASS="COMPUTEROUTPUT">/bin/tcsh</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo $TERM</KBD><SAMPCLASS="COMPUTEROUTPUT">rxvt</SAMP> </PRE></FONT></TD></TR></TABLE> </P></TD></TR></TABLE></DIV></DD></DL></DIV><P></P><DIVCLASS="VARIABLELIST"><P><B>位置参数</B></P><DL><DT><ANAME="POSPARAMREF"></A><CODECLASS="VARNAME">$0</CODE>, <CODECLASS="VARNAME">$1</CODE>, <CODECLASS="VARNAME">$2</CODE>, 等等.</DT><DD><P>位置参数, 从命令行传递到脚本, 或者传递给函数, 或者<AHREF="internal.html#SETREF">set</A>给变量(参见<AHREF="othertypesv.html#EX17">例子 4-5</A>和<AHREF="internal.html#EX34">例子 11-15</A>)</P></DD><DT><CODECLASS="VARNAME">$#</CODE></DT><DD><P>命令行参数 <ANAME="AEN4390"HREF="#FTN.AEN4390"><SPANCLASS="footnote">[2]</SPAN></A> 或者位置参数的个数(参见<AHREF="wrapper.html#EX4">例子 33-2</A>)</P></DD><DT><ANAME="APPREF"></A><CODECLASS="VARNAME">$*</CODE></DT><DD><P>所有的位置参数都被看作为一个单词.</P><DIVCLASS="NOTE"><P></P><TABLECLASS="NOTE"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/note.gif"HSPACE="5"ALT="Note"></TD><TDALIGN="LEFT"VALIGN="TOP"><P><SPANCLASS="QUOTE">"<CODECLASS="VARNAME">$*</CODE>"</SPAN>必须被引用起来.</P></TD></TR></TABLE></DIV></DD><DT><CODECLASS="VARNAME">$@</CODE
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?