textproc.html

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

HTML
3,421
字号
>stdout</TT>. 	      被加入的文件应该事先根据标记域进行排序以便于能够正确的匹配. 	      </P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;File: 1.data  2&nbsp;  3&nbsp;100 Shoes  4&nbsp;200 Laces  5&nbsp;300 Socks</PRE></FONT></TD></TR></TABLE></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;File: 2.data  2&nbsp;  3&nbsp;100 $40.00  4&nbsp;200 $1.00  5&nbsp;300 $2.00</PRE></FONT></TD></TR></TABLE></P><P>	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">join 1.data 2.data</KBD><SAMPCLASS="COMPUTEROUTPUT">File: 1.data 2.data 100 Shoes $40.00 200 Laces $1.00 300 Socks $2.00</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>在输出中标记域将只会出现一次. 	      </P></TD></TR></TABLE></DIV></DD><DT><BCLASS="COMMAND">head</B></DT><DD><P>把文件的头部内容打印到<TTCLASS="FILENAME">stdout</TT>上(默认为<TTCLASS="LITERAL">10</TT>行, 			  可以自己修改). 这个命令有一些比较有趣的选项. 	    <DIVCLASS="EXAMPLE"><HR><ANAME="SCRIPTDETECTOR"></A><P><B>例子 12-12. 哪个文件是脚本?</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# script-detector.sh: 在一个目录中检查所有的脚本文件.   3&nbsp;  4&nbsp;TESTCHARS=2    # 测试前两个字符.  5&nbsp;SHABANG='#!'   # 脚本都是以"#!"开头的.   6&nbsp;  7&nbsp;for file in *  # 遍历当前目录下的所有文件.   8&nbsp;do  9&nbsp;  if [[ `head -c$TESTCHARS "$file"` = "$SHABANG" ]] 10&nbsp;  #      head -c2                      #! 11&nbsp;  #  '-c' 选项将从文件头输出指定个数的字符,  12&nbsp;  #+ 而不是默认的行数.  13&nbsp;  then 14&nbsp;    echo "File \"$file\" is a script." 15&nbsp;  else 16&nbsp;    echo "File \"$file\" is *not* a script." 17&nbsp;  fi 18&nbsp;done 19&nbsp;   20&nbsp;exit 0 21&nbsp; 22&nbsp;#  练习: 23&nbsp;#  ----- 24&nbsp;#  1) 修改这个脚本,  25&nbsp;#+    让它可以指定扫描的路径.  26&nbsp;#+    (而不是只搜索当前目录).  27&nbsp;# 28&nbsp;#  2) 以这个脚本目前的状况, 它不能正确识别出 29&nbsp;#+    Perl, awk, 和其他一些脚本语言的脚本文件. 30&nbsp;#     修正这个问题.</PRE></FONT></TD></TR></TABLE><HR></DIV>	    	    <DIVCLASS="EXAMPLE"><HR><ANAME="RND"></A><P><B>例子 12-13. 产生10-进制随机数</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;# rnd.sh: 输出一个10进制随机数  3&nbsp;  4&nbsp;# 由Stephane Chazelas所编写的这个脚本.  5&nbsp;  6&nbsp;head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p'  7&nbsp;  8&nbsp;  9&nbsp;# =================================================================== # 10&nbsp; 11&nbsp;# 分析 12&nbsp;# ---- 13&nbsp; 14&nbsp;# head: 15&nbsp;# -c4 选项将取得前4个字节. 16&nbsp;                                                17&nbsp;# od: 18&nbsp;# -N4 选项将限制输出为4个字节. 19&nbsp;# -tu4 选项将使用无符号10进制格式来输出. 20&nbsp;                                                21&nbsp;# sed:  22&nbsp;# -n 选项, 使用"s"命令与"p"标志组合的方式, 23&nbsp;# 将会只输出匹配的行. 24&nbsp;                                                25&nbsp;                                                26&nbsp;                                                27&nbsp;# 本脚本作者解释'sed'命令的行为如下. 28&nbsp; 29&nbsp;# head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p' 30&nbsp;# ----------------------------------&#62; | 31&nbsp; 32&nbsp;# 假设一直处理到"sed"命令时的输出--&#62; | 33&nbsp;# 为 0000000 1198195154\n 34&nbsp;                                                                                   35&nbsp;#  sed命令开始读取字串: 0000000 1198195154\n. 36&nbsp;#  这里它发现一个换行符, 37&nbsp;#+ 所以sed准备处理第一行 (0000000 1198195154). 38&nbsp;#  sed命令开始匹配它的&#60;range&#62;和&#60;action&#62;. 第一个匹配的并且只有这一个匹配的: 39&nbsp;                                                                                   40&nbsp;#   range     action 41&nbsp;#   1         s/.* //p 42&nbsp;                                                                                   43&nbsp;#  因为行号在range中, 所以sed开始执行action: 44&nbsp;#+ 替换掉以空格结束的最长的字符串, 在这行中这个字符串是 45&nbsp;#  ("0000000 "), 用空字符串(//)将这个匹配到的字串替换掉, 如果成功, 那就打印出结果 46&nbsp;#  ("p"在这里是"s"命令的标志, 这与单独的"p"命令是不同的). 47&nbsp;                                                                                   48&nbsp;#  sed命令现在开始继续读取输入. (注意在继续之前,  49&nbsp;#+ continuing, 如果没使用-n选项的话, sed命令将再次 50&nbsp;#+ 将这行打印一遍). 51&nbsp;                                                                                   52&nbsp;# 现在, sed命令读取剩余的字符串, 并且找到文件的结尾. 53&nbsp;# sed命令开始处理第2行(这行也被标记为'$' 54&nbsp;# 因为这已经是最后一行). 55&nbsp;# 所以这行没被匹配到&#60;range&#62;中, 这样sed命令就结束了. 56&nbsp;                                                                                   57&nbsp;#  这个sed命令的简短的解释是: 58&nbsp;#  "在第一行中删除第一个空格左边全部的字符, 59&nbsp;#+ 然后打印出来." 60&nbsp;                                                                                   61&nbsp;# 一个更好的来达到这个目的的方法是: 62&nbsp;#           sed -e 's/.* //;q' 63&nbsp;                                                                                   64&nbsp;# 这里, &#60;range&#62;和&#60;action&#62;分别是(也可以写成 65&nbsp;#           sed -e 's/.* //' -e q): 66&nbsp;                                                                                   67&nbsp;#   range                    action 68&nbsp;#   nothing (matches line)   s/.* // 69&nbsp;#   nothing (matches line)   q (quit) 70&nbsp;                                                                                   71&nbsp;#  这里, sed命令只会读取第一行的输入. 72&nbsp;#  将会执行2个命令, 并且会在退出之前打印出(已经替换过的)这行(因为"q" action), 73&nbsp;#+ 因为没使用"-n"选项. 74&nbsp;                                                                                   75&nbsp;# =================================================================== # 76&nbsp;                                                                                   77&nbsp;# 也可以使用如下一个更简单的语句来代替: 78&nbsp;#           head -c4 /dev/urandom| od -An -tu4 79&nbsp; 80&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV>	    	      请参考<AHREF="filearchiv.html#EX52">例子 12-35</A>.</P></DD><DT><BCLASS="COMMAND">tail</B></DT><DD><P>将一个文件结尾部分的内容输出到<TTCLASS="FILENAME">stdout</TT>中(默认为<TTCLASS="LITERAL">10</TT>行). 			通常用来跟踪一个系统logfile的修改情况, 			如果使用<CODECLASS="OPTION">-f</CODE>选项的话, 			这个命令将会继续显示添加到文件中的行. 	      </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX12"></A><P><B>例子 12-14. 使用<BCLASS="COMMAND">tail</B>命令来监控系统log</B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;#!/bin/bash  2&nbsp;  3&nbsp;filename=sys.log  4&nbsp;  5&nbsp;cat /dev/null &#62; $filename; echo "Creating / cleaning out file."  6&nbsp;#  如果文件不存在的话就创建文件,  7&nbsp;#+ 然后将这个文件清空.  8&nbsp;#  : &#62; filename   和   &#62; filename 也能完成这个工作.  9&nbsp; 10&nbsp;tail /var/log/messages &#62; $filename   11&nbsp;# /var/log/messages 必须具有全局的可读权限才行.  12&nbsp; 13&nbsp;echo "$filename contains tail end of system log." 14&nbsp; 15&nbsp;exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="TIP"><P></P><TABLECLASS="TIP"WIDTH="90%"BORDER="0"><TR><TDWIDTH="25"ALIGN="CENTER"VALIGN="TOP"><IMGSRC="./images/tip.gif"HSPACE="5"ALT="Tip"></TD><TDALIGN="LEFT"VALIGN="TOP"><P>为了列出一个文本文件中的指定行的内容, 			可以将<BCLASS="COMMAND">head</B>命令的输出通过<AHREF="special-chars.html#PIPEREF">管道</A>传递到<BCLASS="COMMAND">tail -1</B>中. 		比如<KBDCLASS="USERINPUT">head -8 database.txt | tail		-1</KBD>将会列出<TTCLASS="FILENAME">database.txt</TT>文件第8行的内容. </P><P>下边是将一个文本文件中指定范围的所有行都保存到一个变量中:	        <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;var=$(head -$m $filename | tail -$n)  2&nbsp;  3&nbsp;# filename = 文件名  4&nbsp;# m = 从文件开头到块结尾的行数  5&nbsp;# n = 想保存到变量中的指定行数(从块结尾开始截断)</PRE></FONT></TD></TR></TABLE></P></TD></TR></TABLE></DIV><P>请参考<AHREF="moreadv.html#EX41">例子 12-5</A>, 		  <AHREF="filearchiv.html#EX52">例子 12-35</A>和<AHREF="debugging.html#ONLINE">例子 29-6</A>.</P></DD><DT><ANAME="GREPREF"></A><BCLASS="COMMAND">grep</B></DT><DD><P>使用<AHREF="regexp.html#REGEXREF">正则表达式</A>的一个多用途文本搜索工具. 	      这个命令本来是<BCLASS="COMMAND">ed</B>行编辑器中的一个命令/过滤器: 	      <KBDCLASS="USERINPUT">g/re/p</KBD> -- <EM>global -	      regular expression - print</EM>.</P><P><P><BCLASS="COMMAND">grep</B>   <TTCLASS="REPLACEABLE"><I>pattern</I></TT>  [<TTCLASS="REPLACEABLE"><I>file</I></TT>...]</P>在文件中搜索所有<TTCLASS="REPLACEABLE"><I>pattern</I></TT>出现的位置, 		  <TTCLASS="REPLACEABLE"><I>pattern</I></TT>既可以是要搜索的字符串, 		  也可以是一个正则表达式. 	      </P><P>	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">grep '[rst]ystem.$' osinfo.txt</KBD><SAMPCLASS="COMPUTEROUTPUT">The GPL governs the distribution of the Linux operating system.</SAMP>	      </PRE></FONT></TD></TR></TABLE>	      </P><P>如果没有指定文件参数, 			  <BCLASS="COMMAND">grep</B>通常用在<AHREF="special-chars.html#PIPEREF">管道</A>中对<TTCLASS="FILENAME">stdout</TT>进行过滤. 	      </P><P>	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">ps ax | grep clock</KBD><SAMPCLASS="COMPUTEROUTPUT">765 tty1     S      0:00 xclock 901 pts/1    S      0:00 grep clock</SAMP>	      </PRE></FONT></TD></TR></TABLE>	      </P><P><CODECLASS="OPTION">-i</CODE> 选项在搜索时忽略大小写. </P><P><CODECLASS="OPTION">-w</CODE> 选项用来匹配整个单词. </P><P><CODECLASS="OPTION">-l</CODE> 选项仅列出符合匹配的文件, 			而不列出匹配行. </P><P><CODECLASS="OPTION">-r</CODE> (递归) 选项不仅在当前工作目录下搜索匹配, 			而且搜索子目录. </P><P><CODECLASS="OPTION">-n</CODE> 选项列出所有匹配行, 并显示行号. </P><P>	      <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">grep -n Linux osinfo.txt</KBD><SAMPCLASS="COMPUTEROUTPUT">2:This is a file containing information about Linux. 6:The GPL governs the distribution of the Linux operating system.</SAMP>	      </PRE></FONT></TD></TR></TABLE>	      </P><P><CODECLASS="OPTION">-v</CODE> (或者<CODECLASS="OPTION">--invert-match</CODE>)选项将会显示所有<EM>不匹配的行</EM>.	      <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;grep pattern1 *.txt | grep -v pattern2  2&nbsp;  3&nbsp;# 匹配在"*.txt"中所有包含 "pattern1"的行,   4&nbsp;# 而***不显示***匹配包含"pattern2"的行.	      </PRE></FONT></TD></TR></TABLE></P><P><CODECLASS="OPTION">-c</CODE> (<CODECLASS="OPTION">--count</CODE>)	      选项将只会显示匹配到的行数的总数,而不会列出具体的匹配.	        <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING">  1&nbsp;grep -c txt *.sgml   # (在 "*.sgml" 文件中, 匹配"txt"的行数的总数.)  2&nbsp;  3&nbsp;  4&nbsp;#   grep -cz .  5&nbsp;#            ^ 点  6&nbsp;# 意思是计数 (-c) 所有以空字符分割(-z) 的匹配 "."的项  7&nbsp;# "."是正则表达式的一个符号, 表达匹配任意一个非空字符(至少要包含一个字符).  8&nbsp;#   9&nbsp;printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz .     # 3 10&nbsp;printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '$'   # 5 11&nbsp;printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '^'   # 5 12&nbsp;# 13&nbsp;printf 'a b\nc  d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -c '$'    # 9 14&nbsp;# 默认情况下, 是使用换行符(\n)来分隔匹配项. 15&nbsp; 16&nbsp;# 注意  -z 选项是 GNU "grep" 特定的选项. 17&nbsp; 18&nbsp; 19&nbsp;# 感谢, S.C.</PRE></FONT

⌨️ 快捷键说明

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