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 #!/bin/bash 2 # uppercase.sh : 修改输入, 全部转换为大写. 3 4 tr 'a-z' 'A-Z' 5 # 字符范围必须被""引用起来 6 #+ 来阻止产生单字符的文件名. 7 8 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 cat file1 file2 | ls -l | sort 2 # 从"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 variable="initial_value" 2 echo "new_value" | read variable 3 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">>|</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">&</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B>后台运行命令. </B>一个命令后边跟一个<SPANCLASS="TOKEN">&</SPAN> 表示在后台运行. </P></DIV><P> <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">sleep 10 &</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 #!/bin/bash 2 # background-loop.sh 3 4 for i in 1 2 3 4 5 6 7 8 9 10 # 第一个循环. 5 do 6 echo -n "$i " 7 done & # 在后台运行这个循环. 8 # 在第2个循环之后, 将在某些时候执行. 9 10 echo # 这个'echo'某些时候将不会显示. 11 12 for i in 11 12 13 14 15 16 17 18 19 20 # 第二个循环. 13 do 14 echo -n "$i " 15 done 16 17 echo # 这个'echo'某些时候将不会显示. 18 19 # ====================================================== 20 21 # 期望的输出应该是: 22 # 1 2 3 4 5 6 7 8 9 10 23 # 11 12 13 14 15 16 17 18 19 20 24 25 # 然而实际的结果有可能是: 26 # 11 12 13 14 15 16 17 18 19 20 27 # 1 2 3 4 5 6 7 8 9 10 bozo $ 28 # (第2个'echo'没执行, 为什么?) 29 30 # 也可能是: 31 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 32 # (第1个'echo'没执行, 为什么?) 33 34 # 非常少见的执行结果, 也有可能是: 35 # 11 12 13 1 2 3 4 5 6 7 8 9 10 14 15 16 17 18 19 20 36 # 前台的循环先于后台的执行. 37 38 exit 0 39 40 # Nasimuddin Ansari 建议加一句 sleep 1 41 #+ 在6行和14行的 echo -n "$i" 之后加这句. 42 #+ 为了真正的乐趣.</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">&&</SPAN></DT><DD><DIVCLASS="FORMALPARA"><P><B><AHREF="ops.html#LOGOPS1">与-逻辑操作</A>. </B>在一个<AHREF="testconstructs.html#TESTCONSTRUCTS1">条件测试结构</A>中, 只有在条件测试结构的<EM>两边</EM>结果都为true的时候, <SPANCLASS="TOKEN">&&</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 if [ $file1 -ot $file2 ] 2 then 3 echo "File $file1 is older than $file2." 4 fi 5 6 if [ "$a" -eq "$b" ] 7 then 8 echo "$a is equal to $b." 9 fi 10 11 if [ "$c" -eq 24 -a "$d" -eq 47 ] 12 then 13 echo "$c equals 24 and $d equals 47." 14 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 (cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -) 2 # 从一个目录移动整个目录树到另一个目录 3 # [感谢Alan Cox <a.cox@swansea.ac.uk>, 走出了部分修改] 4 5 # 1) cd /source/directory 源目录 6 # 2) && "与列表": 如果'cd'命令成功了, 那么就执行下边的命令. 7 # 3) tar cf - . 'c'创建一个新文档, 'f'后边跟'-'指定目标文件作为stdout 8 # '-'后边的'f'(file)选项, 指明作为stdout的目标文件. 9 # 并且在当前目录('.')执行. 10 # 4) | 管道... 11 # 5) ( ... ) 一个子shell 12 # 6) cd /dest/directory 改变当前目录到目标目录. 13 # 7) && "与列表", 同上 14 # 8) tar xpvf - 'x'解档, 'p'保证所有权和文件属性, 15 # 'v'发完整消息到stdout, 16 # 'f'后边跟'-',从stdin读取数据. 17 # 18 # 注意:'x' 是一个命令, 'p', 'v', 'f' 是选项. 19 # Whew! 20 21 22 23 # 更优雅的写法应该是: 24 # cd source/directory 25 # tar cf - . | (cd ../dest/directory; tar xpvf -) 26 # 27 # 当然也可以这么写: 28 # cp -a /source/directory/* /dest/directory 29 # 或者: 30 # cp -a /source/directory/* /source/directory/.[^.]* /dest/directory 31 # 如果在/source/directory中有隐藏文件的话.</PRE></FONT></TD></TR></TABLE></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 bunzip2 -c linux-2.6.16.tar.bz2 | tar xvf - 2 # --未解压的tar文件-- | --然后把它传递到"tar"中-- 3 # 如果 "tar" 没能够正常的处理"bunzip2", 4 #+ 这就需要使用管道来执行2个单独的步骤来完成它. 5 # 这个练习的目的是解档"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 #!/bin/bash 2 3 # 在一个"tarball"中(经过tar和gzip处理过的文件) 4 #+ 备份最后24小时当前目录下d所有修改的文件. 5 6 BACKUPFILE=backup-$(date +%m-%d-%Y) 7 # 在备份文件中嵌入时间. 8 # Thanks, Joshua Tschida, for the idea. 9 archive=${1:-$BACKUPFILE} 10 # 如果在命令行中没有指定备份文件的文件名, 11 #+ 那么将默认使用"backup-MM-DD-YYYY.tar.gz". 12 13 tar cvf - `find . -mtime -1 -type f -print` > $archive.tar 14 gzip $archive.tar 15 echo "Directory $PWD backed up in archive file \"$archive.tar.gz\"." 16 17 18 # Stephane Chazelas指出上边代码, 19 #+ 如果在发现太多的文件的时候, 或者是如果文件 20 #+ 名包括空格的时候, 将执行失败. 21 22 # Stephane Chazelas建议使用下边的两种代码之一: 23 # ------------------------------------------------------------------- 24 # find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar" 25 # 使用gnu版本的"find". 26 27 28 # find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \; 29 # 对于其他风格的UNIX便于移植, 但是比较慢. 30 # ------------------------------------------------------------------- 31 32 33 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 + -
显示快捷键?