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 File: 1.data 2 3 100 Shoes 4 200 Laces 5 300 Socks</PRE></FONT></TD></TR></TABLE></P><P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 File: 2.data 2 3 100 $40.00 4 200 $1.00 5 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 #!/bin/bash 2 # script-detector.sh: 在一个目录中检查所有的脚本文件. 3 4 TESTCHARS=2 # 测试前两个字符. 5 SHABANG='#!' # 脚本都是以"#!"开头的. 6 7 for file in * # 遍历当前目录下的所有文件. 8 do 9 if [[ `head -c$TESTCHARS "$file"` = "$SHABANG" ]] 10 # head -c2 #! 11 # '-c' 选项将从文件头输出指定个数的字符, 12 #+ 而不是默认的行数. 13 then 14 echo "File \"$file\" is a script." 15 else 16 echo "File \"$file\" is *not* a script." 17 fi 18 done 19 20 exit 0 21 22 # 练习: 23 # ----- 24 # 1) 修改这个脚本, 25 #+ 让它可以指定扫描的路径. 26 #+ (而不是只搜索当前目录). 27 # 28 # 2) 以这个脚本目前的状况, 它不能正确识别出 29 #+ Perl, awk, 和其他一些脚本语言的脚本文件. 30 # 修正这个问题.</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 #!/bin/bash 2 # rnd.sh: 输出一个10进制随机数 3 4 # 由Stephane Chazelas所编写的这个脚本. 5 6 head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p' 7 8 9 # =================================================================== # 10 11 # 分析 12 # ---- 13 14 # head: 15 # -c4 选项将取得前4个字节. 16 17 # od: 18 # -N4 选项将限制输出为4个字节. 19 # -tu4 选项将使用无符号10进制格式来输出. 20 21 # sed: 22 # -n 选项, 使用"s"命令与"p"标志组合的方式, 23 # 将会只输出匹配的行. 24 25 26 27 # 本脚本作者解释'sed'命令的行为如下. 28 29 # head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p' 30 # ----------------------------------> | 31 32 # 假设一直处理到"sed"命令时的输出--> | 33 # 为 0000000 1198195154\n 34 35 # sed命令开始读取字串: 0000000 1198195154\n. 36 # 这里它发现一个换行符, 37 #+ 所以sed准备处理第一行 (0000000 1198195154). 38 # sed命令开始匹配它的<range>和<action>. 第一个匹配的并且只有这一个匹配的: 39 40 # range action 41 # 1 s/.* //p 42 43 # 因为行号在range中, 所以sed开始执行action: 44 #+ 替换掉以空格结束的最长的字符串, 在这行中这个字符串是 45 # ("0000000 "), 用空字符串(//)将这个匹配到的字串替换掉, 如果成功, 那就打印出结果 46 # ("p"在这里是"s"命令的标志, 这与单独的"p"命令是不同的). 47 48 # sed命令现在开始继续读取输入. (注意在继续之前, 49 #+ continuing, 如果没使用-n选项的话, sed命令将再次 50 #+ 将这行打印一遍). 51 52 # 现在, sed命令读取剩余的字符串, 并且找到文件的结尾. 53 # sed命令开始处理第2行(这行也被标记为'$' 54 # 因为这已经是最后一行). 55 # 所以这行没被匹配到<range>中, 这样sed命令就结束了. 56 57 # 这个sed命令的简短的解释是: 58 # "在第一行中删除第一个空格左边全部的字符, 59 #+ 然后打印出来." 60 61 # 一个更好的来达到这个目的的方法是: 62 # sed -e 's/.* //;q' 63 64 # 这里, <range>和<action>分别是(也可以写成 65 # sed -e 's/.* //' -e q): 66 67 # range action 68 # nothing (matches line) s/.* // 69 # nothing (matches line) q (quit) 70 71 # 这里, sed命令只会读取第一行的输入. 72 # 将会执行2个命令, 并且会在退出之前打印出(已经替换过的)这行(因为"q" action), 73 #+ 因为没使用"-n"选项. 74 75 # =================================================================== # 76 77 # 也可以使用如下一个更简单的语句来代替: 78 # head -c4 /dev/urandom| od -An -tu4 79 80 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 #!/bin/bash 2 3 filename=sys.log 4 5 cat /dev/null > $filename; echo "Creating / cleaning out file." 6 # 如果文件不存在的话就创建文件, 7 #+ 然后将这个文件清空. 8 # : > filename 和 > filename 也能完成这个工作. 9 10 tail /var/log/messages > $filename 11 # /var/log/messages 必须具有全局的可读权限才行. 12 13 echo "$filename contains tail end of system log." 14 15 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 var=$(head -$m $filename | tail -$n) 2 3 # filename = 文件名 4 # m = 从文件开头到块结尾的行数 5 # 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 grep pattern1 *.txt | grep -v pattern2 2 3 # 匹配在"*.txt"中所有包含 "pattern1"的行, 4 # 而***不显示***匹配包含"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 grep -c txt *.sgml # (在 "*.sgml" 文件中, 匹配"txt"的行数的总数.) 2 3 4 # grep -cz . 5 # ^ 点 6 # 意思是计数 (-c) 所有以空字符分割(-z) 的匹配 "."的项 7 # "."是正则表达式的一个符号, 表达匹配任意一个非空字符(至少要包含一个字符). 8 # 9 printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz . # 3 10 printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '$' # 5 11 printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -cz '^' # 5 12 # 13 printf 'a b\nc d\n\n\n\n\n\000\n\000e\000\000\nf' | grep -c '$' # 9 14 # 默认情况下, 是使用换行符(\n)来分隔匹配项. 15 16 # 注意 -z 选项是 GNU "grep" 特定的选项. 17 18 19 # 感谢, S.C.</PRE></FONT
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?