textproc.html
来自「BASH Shell 编程 经典教程 《高级SHELL脚本编程》中文版」· HTML 代码 · 共 3,421 行 · 第 1/5 页
HTML
3,421 行
2 # lookup: 对指定数据文件中的每个单词都做一遍字典查询. 3 4 file=words.data # 指定的要搜索的数据文件. 5 6 echo 7 8 while [ "$word" != end ] # 数据文件中最后一个单词. 9 do 10 read word # 从数据文件中读, 因为在循环的后边重定向了. 11 look $word > /dev/null # 不想将字典文件中的行显示出来. 12 lookup=$? # 'look'命令的退出状态. 13 14 if [ "$lookup" -eq 0 ] 15 then 16 echo "\"$word\" is valid." 17 else 18 echo "\"$word\" is invalid." 19 fi 20 21 done <"$file" # 将stdin重定向到$file, 所以"reads"来自于$file. 22 23 echo 24 25 exit 0 26 27 # ---------------------------------------------------------------- 28 # 下边的代码行将不会执行, 因为上边已经有"exit"命令了. 29 30 31 # Stephane Chazelas建议使用下边更简洁的方法: 32 33 while read word && [[ $word != end ]] 34 do if look "$word" > /dev/null 35 then echo "\"$word\" is valid." 36 else echo "\"$word\" is invalid." 37 fi 38 done <"$file" 39 40 exit 0</PRE></FONT></TD></TR></TABLE><HR></DIV></DD><DT><BCLASS="COMMAND">sed</B>, <BCLASS="COMMAND">awk</B></DT><DD><P>这个两个命令都是独立的脚本语言, 尤其适合分析文本文件和命令输出. 既可以单独使用, 也可以结合管道和在shell脚本中使用. </P></DD><DT><BCLASS="COMMAND"><AHREF="sedawk.html#SEDREF">sed</A></B></DT><DD><P>非交互式的<SPANCLASS="QUOTE">"流编辑器"</SPAN>, 在批处理模式下, 允许使用多个<BCLASS="COMMAND">ex</B>命令. 你会发现它在shell脚本中非常有用. </P></DD><DT><BCLASS="COMMAND"><AHREF="awk.html#AWKREF">awk</A></B></DT><DD><P>可编程的文件提取器和文件格式化工具, 在结构化的文本文件中, 处理或提取特定域(特定列)具有非常好的表现. 它的语法与C语言很类似. </P></DD><DT><BCLASS="COMMAND">wc</B></DT><DD><P><EM>wc</EM>可以统计文件或I/O流中的<SPANCLASS="QUOTE">"单词数量"</SPAN>: <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash $ </SAMP><KBDCLASS="USERINPUT">wc /usr/share/doc/sed-4.1.2/README</KBD><SAMPCLASS="COMPUTEROUTPUT">13 70 447 README</SAMP>[13 lines 70 words 447 characters]</PRE></FONT></TD></TR></TABLE></P><P><KBDCLASS="USERINPUT">wc -w</KBD> 统计单词数量. </P><P><KBDCLASS="USERINPUT">wc -l</KBD> 统计行数量. </P><P><KBDCLASS="USERINPUT">wc -c</KBD> 统计字节数量. </P><P><KBDCLASS="USERINPUT">wc -m</KBD> 统计字符数量. </P><P><KBDCLASS="USERINPUT">wc -L</KBD> 给出文件中最长行的长度. </P><P>使用<BCLASS="COMMAND">wc</B>命令来统计当前工作目录下有多少个<EM>.txt</EM>文件: <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 $ ls *.txt | wc -l 2 # 因为列出的文件名都是以换行符区分的, 所以使用-l来统计. 3 4 5 # 另一种方法: 6 # find . -maxdepth 1 -name \*.txt -print0 | grep -cz . 7 # (shopt -s nullglob; set -- *.txt; echo $#) 8 9 # 感谢, S.C.</PRE></FONT></TD></TR></TABLE> </P><P><BCLASS="COMMAND">wc</B>命令来统计所有以 d - h 开头的文件的大小. <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">wc [d-h]* | grep total | awk '{print $3}'</KBD><SAMPCLASS="COMPUTEROUTPUT">71832</SAMP> </PRE></FONT></TD></TR></TABLE> </P><P>使用<BCLASS="COMMAND">wc</B>命令来查看指定文件中包含<SPANCLASS="QUOTE">"Linux"</SPAN>的行一共有多少. <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">grep Linux abs-book.sgml | wc -l</KBD><SAMPCLASS="COMPUTEROUTPUT">50</SAMP> </PRE></FONT></TD></TR></TABLE> </P><P>请参考<AHREF="filearchiv.html#EX52">例子 12-35</A>和<AHREF="redircb.html#REDIR4">例子 16-8</A>. </P><P>某些命令的某些选项其实已经包含了<BCLASS="COMMAND">wc</B>命令的部分功能. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 ... | grep foo | wc -l 2 # 这个命令使用的非常频繁, 但事实上它有更简便的写法. 3 4 ... | grep -c foo 5 # 只要使用grep命令的"-c"(或"--count")选项就能达到同样的目的. 6 7 # 感谢, S.C.</PRE></FONT></TD></TR></TABLE></P></DD><DT><ANAME="TRREF"></A><BCLASS="COMMAND">tr</B></DT><DD><P>字符转换过滤器. </P><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="special-chars.html#UCREF">必须使用引用或中括号</A>, 这样做才是合理的. 引用可以阻止shell重新解释出现在<BCLASS="COMMAND">tr</B>命令序列中的特殊字符. 中括号应该被引用起来防止被shell扩展. </P></TD></TR></TABLE></DIV><P>无论<KBDCLASS="USERINPUT">tr "A-Z" "*" <filename</KBD>还是<KBDCLASS="USERINPUT">tr A-Z \* <filename</KBD>都可以将<TTCLASS="FILENAME">filename</TT>中的大写字符修改为星号(写到<TTCLASS="FILENAME">stdout</TT>). 但是在某些系统上可能就不能正常工作了, 而<KBDCLASS="USERINPUT">tr A-Z '[**]'</KBD>在任何系统上都可以正常工作. </P><P><CODECLASS="OPTION">-d</CODE>选项删除指定范围的字符. <TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 echo "abcdef" # abcdef 2 echo "abcdef" | tr -d b-d # aef 3 4 5 tr -d 0-9 <filename 6 # 删除"filename"中所有的数字. </PRE></FONT></TD></TR></TABLE></P><P><CODECLASS="OPTION">--squeeze-repeats</CODE> (或<CODECLASS="OPTION">-s</CODE>)选项用来在重复字符序列中除去除第一个字符以外的所有字符. 这个选项在删除多余<AHREF="special-chars.html#WHITESPACEREF">空白</A>的时候非常有用. <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo "XXXXX" | tr --squeeze-repeats 'X'</KBD><SAMPCLASS="COMPUTEROUTPUT">X</SAMP></PRE></FONT></TD></TR></TABLE></P><P><CODECLASS="OPTION">-c</CODE><SPANCLASS="QUOTE">"complement"</SPAN>选项将会<EM>反转</EM>匹配的字符集. 通过这个选项, <BCLASS="COMMAND">tr</B>将只会对那些<EM>不</EM>匹配的字符起作用. </P><P> <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo "acfdeb123" | tr -c b-d +</KBD><SAMPCLASS="COMPUTEROUTPUT">+c+d+b++++</SAMP></PRE></FONT></TD></TR></TABLE> </P><P>注意<BCLASS="COMMAND">tr</B>命令支持<AHREF="x13673.html#POSIXREF">POSIX字符类</A>. <ANAME="AEN8402"HREF="#FTN.AEN8402"><SPANCLASS="footnote">[1]</SPAN></A> </P><P> <TABLEBORDER="1"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="SCREEN"><SAMPCLASS="PROMPT">bash$ </SAMP><KBDCLASS="USERINPUT">echo "abcd2ef1" | tr '[:alpha:]' -</KBD><SAMPCLASS="COMPUTEROUTPUT">----2--1</SAMP> </PRE></FONT></TD></TR></TABLE> </P><DIVCLASS="EXAMPLE"><HR><ANAME="EX49"></A><P><B>例子 12-18. <BCLASS="COMMAND">转换大写</B>: 把一个文件的内容全部转换为大写. </B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # 把一个文件的内容全部转换为大写. 3 4 E_BADARGS=65 5 6 if [ -z "$1" ] # 检查命令行参数. 7 then 8 echo "Usage: `basename $0` filename" 9 exit $E_BADARGS 10 fi 11 12 tr a-z A-Z <"$1" 13 14 # 与上边的作用相同, 但是使用了POSIX字符集标记方法: 15 # tr '[:lower:]' '[:upper:]' <"$1" 16 # 感谢, S.C. 17 18 exit 0 19 20 # 练习: 21 # 重写这个脚本, 通过选项可以控制脚本或者 22 #+ 转换为大写或者转换为小写.</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="LOWERCASE"></A><P><B>例子 12-19. <BCLASS="COMMAND">转换小写</B>: 将当前目录下的所有文全部转换为小写. </B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # 3 # 将当前目录下的所有文全部转换为小写. 4 # 5 # 灵感来自于John Dubois的脚本, 6 #+ Chet Ramey将其转换为Bash脚本, 7 #+ 然后被本书作者精简了一下. 8 9 10 for filename in * # 遍历当前目录下的所有文件. 11 do 12 fname=`basename $filename` 13 n=`echo $fname | tr A-Z a-z` # 将名字修改为小写. 14 if [ "$fname" != "$n" ] # 只对那些文件名不是小写的文件进行重命名. 15 then 16 mv $fname $n 17 fi 18 done 19 20 exit $? 21 22 23 # 下边的代码将不会被执行, 因为上边的"exit". 24 #-------------------------------------------# 25 # 删除上边的内容, 来运行下边的内容. 26 27 # 对于那些文件名中包含空白和新行的文件, 上边的脚本就不能工作了. 28 # Stephane Chazelas因此建议使用下边的方法: 29 30 31 for filename in * # 不必非得使用basename命令, 32 # 因为"*"不会返回任何包含"/"的文件. 33 do n=`echo "$filename/" | tr '[:upper:]' '[:lower:]'` 34 # POSIX 字符集标记法. 35 # 添加的斜线是为了在文件名结尾换行不会被 36 # 命令替换删掉. 37 # 变量替换: 38 n=${n%/} # 从文件名中将上边添加在结尾的斜线删除掉. 39 [[ $filename == $n ]] || mv "$filename" "$n" 40 # 检查文件名是否已经是小写. 41 done 42 43 exit $?</PRE></FONT></TD></TR></TABLE><HR></DIV><DIVCLASS="EXAMPLE"><HR><ANAME="DU"></A><P><B>例子 12-20. <BCLASS="COMMAND">Du</B>: DOS到UNIX文本文件的转换. </B></P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="90%"><TR><TD><FONTCOLOR="#000000"><PRECLASS="PROGRAMLISTING"> 1 #!/bin/bash 2 # Du.sh: DOS到UNIX文本文件的转换. 3 4 E_WRONGARGS=65 5 6 if [ -z "$1" ] 7 then 8 echo "Usage: `basename $0` filename-to-convert" 9 exit $E_WRONGARGS 10 fi 11 12 NEWFILENAME=$1.unx 13 14 CR='\015' # 回车. 15 # 015是8进制的ASCII码的回车. 16 # DOS中文本文件的行结束符是CR-LF. 17 # UNIX中文本文件的行结束符只是LF. 18 19 tr -d $CR < $1 > $NEWFILENAME 20 # 删除回车并且写到新文件中.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?