special-chars.html

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

HTML
4,290
字号
>echo</A>, 传递到一个	      <SPANCLASS="QUOTE">"过滤命令"</SPAN>(在这个过滤命令中将处理输入)中, 然后得到结果. </P><P>  	      <KBDCLASS="USERINPUT">cat $filename1 $filename2 | grep $search_word</KBD>            </P><P></P></DIV></TD></TR></TABLE><P><ANAME="UCREF"></A>当然输出的命令也可以传递到脚本中. 	      <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# uppercase.sh : 修改输入, 全部转换为大写.  3&nbsp;  4&nbsp;tr 'a-z' 'A-Z'  5&nbsp;#  字符范围必须被""引用起来  6&nbsp;#+ 来阻止产生单字符的文件名.  7&nbsp;  8&nbsp;exit 0</PRE></FONT></TD></TR></TABLE>              现在让我们输送<BCLASS="COMMAND">ls -l</B>的输出到一个脚本中. 	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">ls -l | ./uppercase.sh</KBD><SAMPCLASS="COMPUTEROUTPUT">-RW-RW-R--    1 BOZO  BOZO       109 APR  7 19:49 1.TXT -RW-RW-R--    1 BOZO  BOZO       109 APR 14 16:48 2.TXT -RW-R--R--    1 BOZO  BOZO       725 APR 20 20:56 DATA-FILE</SAMP>	      </PRE></FONT></TD></TR></TABLE>	    </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>管道中的每个进程的<TTCLASS="FILENAME">stdout</TT>比须被下一个进程作为<TTCLASS="FILENAME">stdin</TT>来读入. 			 否则, 数据流会<EM>阻塞</EM>, 			 并且管道将产生一些非预期的行为. 	         <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;cat file1 file2 | ls -l | sort  2&nbsp;# 从"cat file1 file2"中的输出并没出现. </PRE></FONT></TD></TR></TABLE>             </P><P>作为<AHREF="othertypesv.html#CHILDREF">子进程</A>的运行的管道, 				 不能够改变脚本的变量.	         <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;variable="initial_value"  2&nbsp;echo "new_value" | read variable  3&nbsp;echo "variable = $variable"     # variable = initial_value</PRE></FONT></TD></TR></TABLE>             </P><P>如果管道中的某个命令产生了一个异常,并中途失败,那么这个管道将过早的终止.			 这种行为被叫做<EM>broken pipe</EM>, 			 并且这种状态下将发送一个<EM>SIGPIPE</EM> <AHREF="debugging.html#SIGNALD">信号</A>.</P></TD></TR></TABLE></DIV></DD><DT><SPANCLASS="TOKEN">&#62;|</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B>强制重定向(即使设置了<AHREF="options.html#NOCLOBBERREF">noclobber选项</A>		-- 就是-C选项). </B>这将强制的覆盖一个现存文件. </P></DIV></DD><DT><SPANCLASS="TOKEN">||</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B><AHREF="ops.html#ORREF">或-逻辑操作</A>. </B>在一个<AHREF="testconstructs.html#TESTCONSTRUCTS1">条件测试结构</A>中, 				如果条件测试结构两边中的<EM>任意一边</EM>结果为true的话, 				<SPANCLASS="TOKEN">||</SPAN>操作就会返回<SPANCLASS="RETURNVALUE">0</SPAN>(代表执行成功). 			</P></DIV></DD><DT><SPANCLASS="TOKEN">&#38;</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B>后台运行命令. </B>一个命令后边跟一个<SPANCLASS="TOKEN">&#38;</SPAN>	        表示在后台运行. </P></DIV><P>	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">sleep 10 &#38;</KBD><SAMPCLASS="COMPUTEROUTPUT">[1] 850</SAMP><SAMPCLASS="COMPUTEROUTPUT">[1]+  Done                    sleep 10</SAMP>	      </PRE></FONT></TD></TR></TABLE>	    </P><P>在一个脚本中,命令和<AHREF="loops1.html#FORLOOPREF1">循环</A>都可能运行在后台. </P><DIVCLASS="EXAMPLE"><HR><ANAME="BGLOOP"></A><P><B>例子 3-3. 在后台运行一个循环</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# background-loop.sh  3&nbsp;  4&nbsp;for i in 1 2 3 4 5 6 7 8 9 10            # 第一个循环.  5&nbsp;do  6&nbsp;  echo -n "$i "  7&nbsp;done &#38; # 在后台运行这个循环.  8&nbsp;       # 在第2个循环之后, 将在某些时候执行.   9&nbsp; 10&nbsp;echo   # 这个'echo'某些时候将不会显示.  11&nbsp; 12&nbsp;for i in 11 12 13 14 15 16 17 18 19 20   # 第二个循环. 13&nbsp;do 14&nbsp;  echo -n "$i " 15&nbsp;done   16&nbsp; 17&nbsp;echo   # 这个'echo'某些时候将不会显示.  18&nbsp; 19&nbsp;# ====================================================== 20&nbsp; 21&nbsp;# 期望的输出应该是: 22&nbsp;# 1 2 3 4 5 6 7 8 9 10  23&nbsp;# 11 12 13 14 15 16 17 18 19 20  24&nbsp; 25&nbsp;# 然而实际的结果有可能是: 26&nbsp;# 11 12 13 14 15 16 17 18 19 20  27&nbsp;# 1 2 3 4 5 6 7 8 9 10 bozo $ 28&nbsp;# (第2个'echo'没执行, 为什么?) 29&nbsp; 30&nbsp;# 也可能是:  31&nbsp;# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 32&nbsp;# (第1个'echo'没执行, 为什么?) 33&nbsp; 34&nbsp;# 非常少见的执行结果, 也有可能是:  35&nbsp;# 11 12 13 1 2 3 4 5 6 7 8 9 10 14 15 16 17 18 19 20  36&nbsp;# 前台的循环先于后台的执行. 37&nbsp; 38&nbsp;exit 0 39&nbsp; 40&nbsp;#  Nasimuddin Ansari 建议加一句 sleep 1 41&nbsp;#+ 在6行和14行的 echo -n "$i" 之后加这句. 42&nbsp;#+ 为了真正的乐趣.</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>在一个脚本内后台运行一个命令,有可能造成这个脚本的挂起,等待一个按键			响应. 幸运的是, 我们有针对这个问题的<AHREF="x6756.html#WAITHANG">解决办法</A>. </P></TD></TR></TABLE></DIV></DD><DT><SPANCLASS="TOKEN">&#38;&#38;</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B><AHREF="ops.html#LOGOPS1">与-逻辑操作</A>. </B>在一个<AHREF="testconstructs.html#TESTCONSTRUCTS1">条件测试结构</A>中, 			只有在条件测试结构的<EM>两边</EM>结果都为true的时候, 			<SPANCLASS="TOKEN">&#38;&#38;</SPAN>操作才会返回<SPANCLASS="RETURNVALUE">0</SPAN>(代表sucess). 		</P></DIV></DD><DT><ANAME="DASHREF"></A><SPANCLASS="TOKEN">-</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B>选项, 前缀. </B>在所有的命令内如果想使用选项参数的话,前边都要加上<SPANCLASS="QUOTE">"-"</SPAN>. </P></DIV><P><KBDCLASS="USERINPUT">COMMAND -[Option1][Option2][...]</KBD></P><P><KBDCLASS="USERINPUT">ls -al</KBD></P><P><KBDCLASS="USERINPUT">sort -dfu $filename</KBD></P><P><KBDCLASS="USERINPUT">set -- $variable</KBD></P><P>	      <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;if [ $file1 -ot $file2 ]  2&nbsp;then  3&nbsp;  echo "File $file1 is older than $file2."  4&nbsp;fi  5&nbsp;  6&nbsp;if [ "$a" -eq "$b" ]  7&nbsp;then  8&nbsp;  echo "$a is equal to $b."  9&nbsp;fi 10&nbsp; 11&nbsp;if [ "$c" -eq 24 -a "$d" -eq 47 ] 12&nbsp;then 13&nbsp;  echo "$c equals 24 and $d equals 47." 14&nbsp;fi</PRE></FONT></TD></TR></TABLE>  	      </P></DD><DT><ANAME="DASHREF2"></A><SPANCLASS="TOKEN">-</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B>用于重定向<TTCLASS="FILENAME">stdin</TT>或<TTCLASS="FILENAME">stdout</TT>[破折号, 即-]. </B><ANAME="COXEX"></A></P></DIV><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;(cd /source/directory &#38;&#38; tar cf - . ) | (cd /dest/directory &#38;&#38; tar xpvf -)  2&nbsp;# 从一个目录移动整个目录树到另一个目录  3&nbsp;# [感谢Alan Cox &#60;a.cox@swansea.ac.uk&#62;, 走出了部分修改]  4&nbsp;  5&nbsp;# 1) cd /source/directory    源目录  6&nbsp;# 2) &#38;&#38;                     "与列表": 如果'cd'命令成功了, 那么就执行下边的命令.   7&nbsp;# 3) tar cf - .              'c'创建一个新文档, 'f'后边跟'-'指定目标文件作为stdout  8&nbsp;#                            '-'后边的'f'(file)选项, 指明作为stdout的目标文件.   9&nbsp;#                            并且在当前目录('.')执行. 10&nbsp;# 4) |                       管道... 11&nbsp;# 5) ( ... )                 一个子shell 12&nbsp;# 6) cd /dest/directory      改变当前目录到目标目录. 13&nbsp;# 7) &#38;&#38;                     "与列表", 同上 14&nbsp;# 8) tar xpvf -              'x'解档, 'p'保证所有权和文件属性, 15&nbsp;#                            'v'发完整消息到stdout, 16&nbsp;#                            'f'后边跟'-',从stdin读取数据.  17&nbsp;# 18&nbsp;#                            注意:'x' 是一个命令, 'p', 'v', 'f' 是选项. 19&nbsp;# Whew! 20&nbsp; 21&nbsp; 22&nbsp; 23&nbsp;# 更优雅的写法应该是: 24&nbsp;#   cd source/directory 25&nbsp;#   tar cf - . | (cd ../dest/directory; tar xpvf -) 26&nbsp;# 27&nbsp;#     当然也可以这么写: 28&nbsp;# cp -a /source/directory/* /dest/directory 29&nbsp;#     或者: 30&nbsp;# cp -a /source/directory/* /source/directory/.[^.]* /dest/directory 31&nbsp;#     如果在/source/directory中有隐藏文件的话.</PRE></FONT></TD></TR></TABLE></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;bunzip2 -c linux-2.6.16.tar.bz2 | tar xvf -  2&nbsp;#  --未解压的tar文件--    | --然后把它传递到"tar"中--  3&nbsp;#  如果 "tar" 没能够正常的处理"bunzip2",  4&nbsp;#+ 这就需要使用管道来执行2个单独的步骤来完成它.  5&nbsp;#  这个练习的目的是解档"bzipped"的kernel源文件.</PRE></FONT></TD></TR></TABLE></P><P>注意, 在这个上下文中<SPANCLASS="QUOTE">"-"</SPAN>本身并不是一个Bash操作, 	而是一个可以被特定的UNIX工具识别的选项, 	这些特定的UNIX工具特指那些可以写输出到<TTCLASS="FILENAME">stdout</TT>的工具, 	    比如<BCLASS="COMMAND">tar</B>, <BCLASS="COMMAND">cat</B>, 等等.</P><P>	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo "whatever" | cat -</KBD><SAMPCLASS="COMPUTEROUTPUT">whatever</SAMP> </PRE></FONT></TD></TR></TABLE>	    </P><P>在需要一个文件名的位置, 			<TTCLASS="REPLACEABLE"><I>-</I></TT>重定向输出到<TTCLASS="FILENAME">stdout</TT>(有时候会在<KBDCLASS="USERINPUT">tar和cf</KBD>中出现), 			或者从<TTCLASS="FILENAME">stdin</TT>接受输入, 而不是从一个文件中接受输入. 			这是在管道中使用文件导向(file-oriented)工具来作为过滤器的一种方法. </P><P>	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">file</KBD><SAMPCLASS="COMPUTEROUTPUT">Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...</SAMP>	      </PRE></FONT></TD></TR></TABLE>	    在命令行上单独给出一个<AHREF="filearchiv.html#FILEREF">file</A>, 会给出一个错误信息.	    </P><P>			添加一个<SPANCLASS="QUOTE">"-"</SPAN>将得到一个更有用的结果. 			这会使shell等待用户输入.	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">file -</KBD><KBDCLASS="USERINPUT">abc</KBD><SAMPCLASS="COMPUTEROUTPUT">standard input:              ASCII text</SAMP><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">file -</KBD><KBDCLASS="USERINPUT">#!/bin/bash</KBD><SAMPCLASS="COMPUTEROUTPUT">standard input:              Bourne-Again shell script text executable</SAMP>	      </PRE></FONT></TD></TR></TABLE>	      现在命令从<TTCLASS="FILENAME">stdin</TT>中接受了输入, 并分析它.	    </P><P><SPANCLASS="QUOTE">"-"</SPAN>可以被用来将<TTCLASS="FILENAME">stdout</TT>通过管道传递到其他命令中. 			这样就允许使用<AHREF="assortedtips.html#PREPENDREF">在一个文件开头添加几行</A>的技巧. </P><P>使用<AHREF="filearchiv.html#DIFFREF">diff</A>命令来和另一个文件的<EM>某一段</EM>进行比较: </P><P><KBDCLASS="USERINPUT">grep Linux file1 | diff file2 -</KBD></P><P>最后, 来展示一个使用<TTCLASS="REPLACEABLE"><I>-</I></TT>的<AHREF="filearchiv.html#TARREF">tar</A>命令的一个真实的例子.</P><DIVCLASS="EXAMPLE"><HR><ANAME="EX58"></A><P><B>例子 3-4. 备份最后一天所有修改的文件</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;#  在一个"tarball"中(经过tar和gzip处理过的文件)  4&nbsp;#+ 备份最后24小时当前目录下d所有修改的文件.   5&nbsp;  6&nbsp;BACKUPFILE=backup-$(date +%m-%d-%Y)  7&nbsp;#                 在备份文件中嵌入时间.  8&nbsp;#                 Thanks, Joshua Tschida, for the idea.  9&nbsp;archive=${1:-$BACKUPFILE} 10&nbsp;#  如果在命令行中没有指定备份文件的文件名, 11&nbsp;#+ 那么将默认使用"backup-MM-DD-YYYY.tar.gz". 12&nbsp; 13&nbsp;tar cvf - `find . -mtime -1 -type f -print` &#62; $archive.tar 14&nbsp;gzip $archive.tar 15&nbsp;echo "Directory $PWD backed up in archive file \"$archive.tar.gz\"." 16&nbsp; 17&nbsp; 18&nbsp;#  Stephane Chazelas指出上边代码, 19&nbsp;#+ 如果在发现太多的文件的时候, 或者是如果文件 20&nbsp;#+ 名包括空格的时候, 将执行失败. 21&nbsp; 22&nbsp;# Stephane Chazelas建议使用下边的两种代码之一: 23&nbsp;# ------------------------------------------------------------------- 24&nbsp;#   find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar" 25&nbsp;#      使用gnu版本的"find". 26&nbsp; 27&nbsp; 28&nbsp;#   find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \; 29&nbsp;#         对于其他风格的UNIX便于移植, 但是比较慢. 30&nbsp;# ------------------------------------------------------------------- 31&nbsp; 32&nbsp; 33&nbsp;exit 0</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>以<SPANCLASS="QUOTE">"-"</SPAN>开头的文件名在使用<SPANCLASS="QUOTE">"-"</SPAN>作为重定向操作符的时候, 				可能会产生问题. 应该写一个脚本来检查这个问题, 并给这个文件加上合适的前缀. 	      比如: <TTCLASS="FILENAME">./-FILENAME</TT>, 	      <TTCLASS="FILENAME">$PWD/-FILENAME</TT>, 或者 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?