internalvariables.html

来自「BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版」· HTML 代码 · 共 3,354 行 · 第 1/4 页

HTML
3,354
字号
COLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;E_WRONG_DIRECTORY=73  4&nbsp;  5&nbsp;clear # 清屏.  6&nbsp;  7&nbsp;TargetDirectory=/home/bozo/projects/GreatAmericanNovel  8&nbsp;  9&nbsp;cd $TargetDirectory 10&nbsp;echo "Deleting stale files in $TargetDirectory." 11&nbsp; 12&nbsp;if [ "$PWD" != "$TargetDirectory" ] 13&nbsp;then    # 防止偶然删错目录. 14&nbsp;  echo "Wrong directory!" 15&nbsp;  echo "In $PWD, rather than $TargetDirectory!" 16&nbsp;  echo "Bailing out!" 17&nbsp;  exit $E_WRONG_DIRECTORY 18&nbsp;fi   19&nbsp; 20&nbsp;rm -rf * 21&nbsp;rm .[A-Za-z0-9]*    # 删除点文件(译者注: 隐藏文件).  22&nbsp;# rm -f .[^.]* ..?*   为了删除以多个点开头的文件.  23&nbsp;# (shopt -s dotglob; rm -f *)   也可以. 24&nbsp;# 感谢, S.C. 指出这点. 25&nbsp; 26&nbsp;# 文件名可以包含ascii中0 - 255范围内的所有字符, 除了"/". 27&nbsp;# 删除以各种诡异字符开头的文件将会作为一个练习留给大家. 28&nbsp; 29&nbsp;# 如果必要的话, 这里预留给其他操作. 30&nbsp; 31&nbsp;echo 32&nbsp;echo "Done." 33&nbsp;echo "Old files deleted in $TargetDirectory." 34&nbsp;echo 35&nbsp; 36&nbsp; 37&nbsp;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&nbsp;#!/bin/bash  2&nbsp;# reply.sh  3&nbsp;  4&nbsp;# REPLY是提供给'read'命令的默认变量.  5&nbsp;  6&nbsp;echo  7&nbsp;echo -n "What is your favorite vegetable? "  8&nbsp;read  9&nbsp; 10&nbsp;echo "Your favorite vegetable is $REPLY." 11&nbsp;#  当且仅当没有变量提供给"read"命令时,  12&nbsp;#+ REPLY才保存最后一个"read"命令读入的值. 13&nbsp; 14&nbsp;echo 15&nbsp;echo -n "What is your favorite fruit? " 16&nbsp;read fruit 17&nbsp;echo "Your favorite fruit is $fruit." 18&nbsp;echo "but..." 19&nbsp;echo "Value of \$REPLY is still $REPLY." 20&nbsp;#  $REPLY还是保存着上一个read命令的值, 21&nbsp;#+ 因为变量$fruit被传入到了这个新的"read"命令中. 22&nbsp; 23&nbsp;echo 24&nbsp; 25&nbsp;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&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;TIME_LIMIT=10  4&nbsp;INTERVAL=1  5&nbsp;  6&nbsp;echo  7&nbsp;echo "Hit Control-C to exit before $TIME_LIMIT seconds."  8&nbsp;echo  9&nbsp; 10&nbsp;while [ "$SECONDS" -le "$TIME_LIMIT" ] 11&nbsp;do 12&nbsp;  if [ "$SECONDS" -eq 1 ] 13&nbsp;  then 14&nbsp;    units=second 15&nbsp;  else   16&nbsp;    units=seconds 17&nbsp;  fi 18&nbsp; 19&nbsp;  echo "This script has been running $SECONDS $units." 20&nbsp;  #  在一台比较慢或者是附载过大的机器上,  21&nbsp;  #+ 在单次循环中, 脚本可能会忽略计数.  22&nbsp;  sleep $INTERVAL 23&nbsp;done 24&nbsp; 25&nbsp;echo -e "\a"  # Beep!(哔哔声!) 26&nbsp; 27&nbsp;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&nbsp;# 只能够在Bash脚本中使用, 必须使用2.05b或之后版本的Bash.  2&nbsp;  3&nbsp;TMOUT=3    # 提示输入时间为3秒.  4&nbsp;  5&nbsp;echo "What is your favorite song?"  6&nbsp;echo "Quickly now, you only have $TMOUT seconds to answer!"  7&nbsp;read song  8&nbsp;  9&nbsp;if [ -z "$song" ] 10&nbsp;then 11&nbsp;  song="(no answer)" 12&nbsp;  # 默认响应. 13&nbsp;fi 14&nbsp; 15&nbsp;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&nbsp;#!/bin/bash  2&nbsp;# timed-input.sh  3&nbsp;  4&nbsp;# TMOUT=3    在新一些的Bash版本上也能运行的很好.  5&nbsp;  6&nbsp;  7&nbsp;TIMELIMIT=3  # 这个例子中设置的是3秒. 也可以设置为其他的时间值.  8&nbsp;  9&nbsp;PrintAnswer() 10&nbsp;{ 11&nbsp;  if [ "$answer" = TIMEOUT ] 12&nbsp;  then 13&nbsp;    echo $answer 14&nbsp;  else       # 别和上边的例子弄混了. 15&nbsp;    echo "Your favorite veggie is $answer" 16&nbsp;    kill $!  # 不再需要后台运行的TimerOn函数了, kill了吧. 17&nbsp;             # $! 变量是上一个在后台运行的作业的PID. 18&nbsp;  fi 19&nbsp; 20&nbsp;}   21&nbsp; 22&nbsp; 23&nbsp; 24&nbsp;TimerOn() 25&nbsp;{ 26&nbsp;  sleep $TIMELIMIT &#38;&#38; kill -s 14 $$ &#38; 27&nbsp;  # 等待3秒, 然后给脚本发送一个信号. 28&nbsp;}   29&nbsp; 30&nbsp;Int14Vector() 31&nbsp;{ 32&nbsp;  answer="TIMEOUT" 33&nbsp;  PrintAnswer 34&nbsp;  exit 14 35&nbsp;}   36&nbsp; 37&nbsp;trap Int14Vector 14   # 定时中断(14)会暗中给定时间限制.  38&nbsp; 39&nbsp;echo "What is your favorite vegetable " 40&nbsp;TimerOn 41&nbsp;read answer 42&nbsp;PrintAnswer 43&nbsp; 44&nbsp; 45&nbsp;#  无可否认, 这是一个定时输入的复杂实现, 46&nbsp;#+ 然而"read"命令的"-t"选项可以简化这个任务.  47&nbsp;#  参考后边的"t-out.sh". 48&nbsp; 49&nbsp;#  如果你需要一个真正优雅的写法... 50&nbsp;#+ 建议你使用C或C++来重写这个应用, 51&nbsp;#+ 你可以使用合适的函数库, 比如'alarm'和'setitimer'来完成这个任务. 52&nbsp; 53&nbsp;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&nbsp;#!/bin/bash  2&nbsp;# timeout.sh  3&nbsp;  4&nbsp;#  由Stephane Chazelas所编写,  5&nbsp;#+ 本书作者做了一些修改.  6&nbsp;  7&nbsp;INTERVAL=5                # 超时间隔  8&nbsp;  9&nbsp;timedout_read() { 10&nbsp;  timeout=$1 11&nbsp;  varname=$2 12&nbsp;  old_tty_settings=`stty -g` 13&nbsp;  stty -icanon min 0 time ${timeout}0 14&nbsp;  eval read $varname      # 或者仅仅读取$varname变量 15&nbsp;  stty "$old_tty_settings" 16&nbsp;  # 参考"stty"的man页. 17&nbsp;} 18&nbsp; 19&nbsp;echo; echo -n "What's your name? Quick! " 20&nbsp;timedout_read $INTERVAL your_name 21&nbsp; 22&nbsp;#  这种方法可能并不是在每种终端类型上都可以正常使用的. 23&nbsp;#  最大的超时时间依赖于具体的中断类型. 24&nbsp;#+ (通常是25.5秒). 25&nbsp; 26&nbsp;echo 27&nbsp; 28&nbsp;if [ ! -z "$your_name" ]  # 如果在超时之前名字被键入... 29&nbsp;then 30&nbsp;  echo "Your name is $your_name." 31&nbsp;else 32&nbsp;  echo "Timed out." 33&nbsp;fi 34&nbsp; 35&nbsp;echo 36&nbsp; 37&nbsp;# 这个脚本的行为可能与脚本"timed-input.sh"的行为有些不同. 38&nbsp;# 每次按键, 计时器都会重置(译者注: 就是从0开始). 39&nbsp; 40&nbsp;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&nbsp;#!/bin/bash  2&nbsp;# t-out.sh  3&nbsp;# 从"syngin seven"的建议中得到的灵感 (感谢).  4&nbsp;  5&nbsp;  6&nbsp;TIMELIMIT=4         # 4秒  7&nbsp;  8&nbsp;read -t $TIMELIMIT variable &#60;&#38;1  9&nbsp;#                           ^^^ 10&nbsp;#  在这个例子中, 对于Bash 1.x和2.x就需要"&#60;&#38;1"了, 11&nbsp;#  但是Bash 3.x就不需要. 12&nbsp; 13&nbsp;echo 14&nbsp; 15&nbsp;if [ -z "$variable" ]  # 值为null? 16&nbsp;then 17&nbsp;  echo "Timed out, variable still unset." 18&nbsp;else   19&nbsp;  echo "variable = $variable" 20&nbsp;fi   21&nbsp; 22&nbsp;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&nbsp;#!/bin/bash  2&nbsp;# am-i-root.sh:   我是不是root用户?  3&nbsp;  4&nbsp;ROOT_UID=0   # Root的$UID为0.  5&nbsp;  6&nbsp;if [ "$UID" -eq "$ROOT_UID" ]  # 只有真正的"root"才能经受得住考验?  7&nbsp;then  8&nbsp;  echo "You are root."  9&nbsp;else 10&nbsp;  echo "You are just an ordinary user (but mom loves you just the same)." 11&nbsp;fi 12&nbsp; 13&nbsp;exit 0 14&nbsp; 15&nbsp; 16&nbsp;# ============================================= # 17&nbsp;# 下边的代码不会执行, 因为脚本在上边已经退出了. 18&nbsp; 19&nbsp;# 下边是另外一种判断root用户的方法: 20&nbsp; 21&nbsp;ROOTUSER_NAME=root 22&nbsp; 23&nbsp;username=`id -nu`              # 或者...   username=`whoami` 24&nbsp;if [ "$username" = "$ROOTUSER_NAME" ] 25&nbsp;then 26&nbsp;  echo "Rooty, toot, toot. You are root." 27&nbsp;else 28&nbsp;  echo "You are just a regular fella." 29&nbsp;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 + -
显示快捷键?