外部过滤器,程序和命令--文本处理命令

处理文本和文本文件的命令

sort

  文本排序,通常用在管道中当作过滤器来使用. 这个命令可以依据指定的关键字或指定的字符位置,对文件进行排序. 使用-m选项,它将会合并预排序的输入文件.


tsort

  拓扑排序, 读取以空格分隔的有序对, 并且依靠输入模式进行排序.

uniq

  这个过滤器将会删除一个已排序文件中的重复行. 这个命令经常出现在sort命令的管道后边.

cat list-1 list-2 list-3 | sort | uniq > final.list
# 把3个文件连接起来,将它们排序,
# 删除其中重复的行,最后将结果重定向到一个文件中.

  -c用来统计每行出现的次数,并把次数作为前缀放到输出行的前面.

bash$ cat testfile
This line occurs only once.
This line occurs twice.
This line occurs twice.
This line occurs three times.
This line occurs three times.
This line occurs three times.

bash$ uniq -c testfile
    1 This line occurs only once.
    2 This line occurs twice.
    3 This line occurs three times.

  sort INPUTFILE | uniq -c | sort -nr命令先对INPUTFILE文件进行排序,然后统计出每行出现的次数(sort 命令的-nr 选项会产生一个数字的反转排序). 这种命令模板一般都用来分析log文件或者用来分析字典列表,或者用在那些需要检查文本词汇结构的地方.


例:分析单词出现的频率.

#!/bin/bash
# wf.sh: 分析文本文件中词汇出现的频率.

ARGS=1
E_BADARGS=65
E_NOFILE=66

if [ $# -ne "$ARGS" ]
then
    echo "Usage: `basename $0` filename"
    exit $E_BADARGS
fi

if [ ! -f "$1" ]
then
    echo "File \"$1\" does not exist."
    exit $E_NOFILE
fi

sed -e 's/\.//g' -e 's/\,//g' -e 's/ /\
        /g' "$1" | tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr
#                                   =======================
#                                     检查单词出现的频率 

#  过滤掉句号和逗号,
#+ 并且把单词间的空格转化为换行,
#+ 然后转化为小写,
#+ 最后统计单词出现的频率并按频率排序.

exit 0

运行:

bash$ cat testfile
This line occurs only once.
This line occurs twice.
This line occurs twice.
This line occurs three times.
This line occurs three times.
This line occurs three times.

bash$ ./wf.sh testfile
      6 this
      6         occurs
      6         line
      3         times
      3         three
      2         twice
      1         only
      1         once

expand, unexpand

  expand命令将会把每个tab转化为一个空格. 这个命令经常用在管道中.

  unexpand命令将会把每个空格转化为一个tab. 效果与expand命令相反.


cut

  一个从文件中提取特定域的工具. 这个命令与awk中使用的 print $N 命令很相似, 但是更受限. 在脚本中使用cut命令会比使用awk命令来得容易一些. 最重要的选项就是 -d (字段定界符)和 -f (域分隔符)选项.

  使用cut来获得所有mount上的文件系统的列表:

cut -d ' ' -f1,2 /etc/mtab

  使用cut命令列出OS和内核版本.

uname -a | cut -d " " -f1,2,11,12

  使用cut命令来分析一个文件:

#!/bin/bash
# 列出所有在/etc/passwd中的用户.

FILENAME=/etc/passwd

for user in $(cut -d: -f1 $FILENAME) 
do
    echo $user
done

exit 0

  cut -d ’ ’ -f2,3 filename等价于awk -F’[ ]’ ‘{print $2, $3}’ filename

  你甚至可以指定换行符作为字段定界符. 这个小伎俩实际上就是在命令行上插入一个换行(RETURN). (linux使用lf作为换行符).

bash$ cut -d '
' -f3,7,19 testfile
This is line 3 of testfile.
This is line 7 of testfile.
This is line 19 of testfile.

paste

  将多个文件, 以每个文件一列的形式合并到一个文件中, 合并后文件中的每一列就是原来的一个文件.与cut结合使用, 经常用于创建系统log文件.


join

  与paste命令属于同类命令. 但是它能够完成某些特殊的目地. 这个强力工具能够以一种特殊的形式来合并两个文件, 这种特殊的形式本质上就是一个关联数据库的简单版本.

  join命令只能够操作两个文件. 它可以将那些具有特定标记域(通常是一个数字标签)的行合并起来, 并且将结果输出到 stdout . 被加入的文件应该事先根据标记域进行排序以便于能够正确的匹配.

bash$ cat 1.data
100 Shoes
200 Laces
300 Socks

bash$ cat 2.data
100 $40.00
200 $1.00
300 $2.00

bash$ join 1.data 2.data
100 Shoes $40.00
200 Laces $1.00
300 Socks $2.00

  * 在输出中标记域只会出现一次.


  把文件的头部内容打印到stdout上(默认是10行,可以自己修改).


例:哪个是脚本文件.

#!/bin/bash
# script-detector.sh: 在一个目录中检查所有的脚本文件.

TESTCHARS=2         # 测试前两个字符.
SHABANG='#!'        # 脚本都是以'#!'开头的.

for file in *
do
    if [[ `head -c$TESTCHARS "$file"` = "$SHABANG" ]]
#       head -c2  '-c'选项将从文件头输出指定个数的字符,而不是默认的行数.
    then
        echo "File \"$file\" is a script."
    else
        echo "File \"$file\" is *not* a script."
    fi
done

exit 0

  
例:产生10-进制随机数.

#!/bin/bash
# rnd.sh: 输出一个10进制随机数.

head -c4 /dev/urandom | od -N4 -tu4 | sed -ne '1s/.* //p'
#  head: 
#+ -c4 选项将取得前4个字节.

#  od:
#+ -N4 选项将限制输出为4个字节.
#+ -tu4 选项将使用无符号的10进制格式来输出.

#  sed:
#+ -n 选项,使用"s"命令与"p"标志组合的方式,将只输出匹配的行.

exit 0

tail

  将一个文件结尾部分的内容输出到stdout中(默认为10行). 通常用来跟踪一个系统logfile的修改情况,如果使用 -f 选项的话,这个命令将会继续显示添加到文件中的行.

  为了列出一个文本文件中的指定行的内容, 可以将head命令的输出通过管道传递到tail -1中. 比如 head -8 database.txt | tail -1 将会列出 database.txt 文件第8行的内容.

  下边是将一个文本文件中指定范围的所有行都保存到一个变量中:

var=$(head -$m $filename | tail -$n)

# filename = 文件名.
# m = 从文件开头到块结尾的行数.
# n = 想保存到变量中的指定行数(从块结尾开始截断).

grep

  使用正则表达式的一个多用途文本搜索工具. 这个命令本来是ed行编辑器中的一个命令/过滤器:
  g/re/p – global - regualr expression - print.

  grep pattern [file…]
  在文件中搜索所有 pattern 出现的位置, pattern 既可以是要搜索的字符串, 也可以是一个正则表达式.

bash$ grep '[rst]ystem.$' osinfo.txt
The GPL governs the distribution of the Linux operating system.

  如果没有指定文件参数,grep通常用在管道中对stdout进行过滤.

bash$ ps ax | grep clock
18779 pts/19   S+     0:00 grep --color=auto clock

  -i 选项在搜索时忽略大小写.

  -w 选项用来匹配整个单词.

  -l 选项仅列出符合匹配的文件, 而不列出匹配行.

  -r (递归)选项不仅在当前工作目录下搜索匹配, 而且搜索子目录.

  -n 选项列出所有匹配行, 并显示行号.

  -v (或者–invert-match)选项将会显示所有不匹配的行.

grep pattern1 *.txt | grep -v pattern2
# 匹配在"*.txt"中所有包含"pattern1"的行,
# 而不显示匹配包含"pattern2"的行.

  -c ( –count ) 选项将只会显示匹配到的行数的总数,而不会列出具体的匹配.
  当有多个文件参数的时候, grep将会指出哪个文件中包含具体的匹配.

  如果在grep命令只搜索一个文件的时候, 那么可以简单的把 /dev/null 作为第二个文件参数传递给grep.

bash$ grep Linux osinfo.txt /dev/null
osinfo.txt:This is a file containing information about Linux.
osinfo.txt:The GPL governs the distribution of the Linux
operating system.

  如果存在一个成功的匹配, 那么grep命令将会返回0作为退出状态码, 这样就可以将grep命令的结果放在脚本的条件测试中来使用, 尤其和 -q (禁止输出)选项组合时特别有用.

SUCCESS=0           # 如果grep匹配成功.
word=Linux
filename=data.file

grep -q "$word" "$filename" # "-q"选项使得什么都不输出到stdout上.

if [ $? -eq $SUCCESS ]
# if grep -q "$word" "$filename" 与上面等价.
then
    echo "$word found in $filename."
else
    echo "$word not found in $filename."
fi

  如何使用grep命令来搜索两个(或两个以上)独立的模式? 如果你想在一个或多个文件中显示既匹配”pattern1”又匹配”pattern2”的所有匹配的话, 那又该如何做呢?
  比如,给定如下文件:

# 文件名:testfile

This is a sample file.
This is an ordinary text file.
This file does not contain any unusual text.
This file is not unusual.
/...

现在,让我们在这个文件中搜索既包含”file”又包含”text”的所有行.

bash$ grep file testfile
This is a simple file.
This is an oridinary text file.
Tshi file does not contain any unusual text.
This file is not usual.

bash$ grep file testfile | grep text
This is an oridinary text file.
This file does not contain any unusual text.

egrep

  扩展的grep - 这个命令与grep -E等价. 这个命令用起来有些不同, 由于使用正则表达式的扩展集合, 将会使得搜索更具灵活性. 它也允许逻辑|(或)操作.

bash$ egrep 'matches|Matches' file.txt
Line 1 matches.
Line 3 Matches.
Line 4 contains matches,but also Matches.

fgrep

  快速的grep - 这个命令与grep -F等价.这是一种按照字符串字面意思进行的搜索(即不允许使用正则表达式), 这样有时候会使搜索变得容易一些.

  * 在某些Linux发行版中, egrep和fgrep都是grep命令的符号链接或者别名, 只不过在调用的时候分别使用了 -E 和 -F 选项罢了.


agrep

   (近似grep)扩展了grep近似匹配的能力.搜索的字符串可能会与最终匹配结果所找到字符串有些不同. 这个工具并不是核心Linux发行版的一部分.

  ! 为了搜索压缩文件, 应使用zgrep, zegrep, 或zfgrep. 这些命令也可以对未压缩的文件进行搜索, 只不过会比一般的grep, egrep, 和fgrep慢上一些. 当然, 在你要搜索的文件中如果混合了压缩和未压缩的文件的话, 那么使用这些命令是非常方便的.

  ! 如果要搜索bzipped类型的文件, 使用bzgrep.


look

  look命令与grep命令很相似,但是这个命令只能做”字典查询”,也就是它所搜索的文件必须是已经排过序的单词列表.默认情况下, 如果没有指定搜索哪个文件, look命令就默认搜索 /usr/dict/words (或者应该是/usr/share/dict/words ), 当然也可以指定其他目录下的文件进行搜索.


sed, awk

  这个两个命令都是独立的脚本语言, 尤其适合分析文本文件和命令输出. 既可以单独使用, 也可以结合管道和在shell脚本中使用.

sed

  非交互式的”流编辑器”, 在批处理模式下, 允许使用多个ex命令. 你会发现它在shell脚本中非常有用.

awk

  可编程的文件提取器和文件格式化工具, 在结构化的文本文件中, 处理或提取特定域(特定列)具有非常好的表现. 它的语法与C语言很类似.

wc

  wc可以统计文件或I/O流中的”单词数量”:

bash$ wc /usr/share/doc/sed-4.1.2/README
13  70  447 README
[13 lines 70 words 447 characters]

  wc -w 统计单词数量.
  wc -l 统计行数量.
  wc -c 统计字节数量.
  wc -m 统计字符数量.
  wc -L 给出文件中最长行的长度.

  使用wc命令来统计当前工作目录下有多少个.txt文件:

bash$ ls *.txt | wc -l
# 因为列出的文件名是以换行符区分的,所以使用-l统计.

# 另一种方法:
# find . -maxdepth 1 -name \*.txt -print0 | grep -cz.
# (shopt -s nullglob; set -- *.txt; echo $#)

  wc命令来统计所有以d - h 开头的文件的大小.

bash$ wc [d-h]* | grep total | awk '{print $3}'
71832

  使用wc命令来查看指定文件中包含”Linux”的行一共有多少.

bash$ grep Linux abs-book.sgml | wc -l
50

tr

  字符转换过滤器.
  必须使用引用或中括号, 这样做才是合理的. 引用可以阻止shell重新解释出现在tr命令序列中的特殊字符. 中括号应该被引用起来防止被shell扩展.

  无论tr "A-Z" "*" <filename还是tr A-Z \* <filename都可以将filename中的大写字母修改为星号(写到stdout). 但是在某些系统上可能就不能正常工作了,而tr A-Z '[**]' 在任何系统上都可以正常工作.

  -d 选项删除指定范围的字符.

echo "abcdef"                   # abcdef
echo "abcdefedcba" | tr -d b-d      # aefea

tr -d 0-9 <filename
# 删除"filename"中所有的数字.

  - -squeeze-repeats(或-s )选项用来在重复字符序列中除去除第一个字符以外的所有字符. 这个选项在删除多余空白的时候非常有用.

bash$ echo "XXXXX" | tr --squeeze-repeats 'X'
X

  -c “complement”选项将会反转匹配的字符集.通过这个选项, tr将只会对那些不匹配的字符起作用.

bash$ echo "acfdeb123" | tr -c b-d +
+c+d+b++++
# 最后为什么是4个+?

  tr命令支持POSIX字符类.

bash$ echo "abcd2ef1" | tr '[:alpha:]' -
----2--1

例:转换大写:把一个文件的内容全部转换为大写.

#!/bin/bash
# tra-A.sh: 把一个文件的内容全部转化为大写.

E_BADARGS=65

if [ -z "$1" ]
then 
    echo "Usage: `basename $0` filename"
    exit $E_BADARGS
fi

tr a-z A-Z <"$1"

exit 0

运行:

cat file
abcdefghijklmn

bash$ ./tra-A.sh file
ABCDEFGHIJKLMN

例:rot13:rot13, 弱智加密.

#!/bin/bash
# rot13.sh: 典型的rot13算法.

# 用法  ./rot13.sh filename
# 或    ./rot13.sh <filename  
# 或    ./rot13.sh and supply keyboard input (stdin)

cat "$@" | tr 'a-zA-Z' 'n-za-mN-ZA-M'
# "a"变为"n","b"变为"o",等等.
# 'cat "$@"'结构允许从stdin或文件中获得输入.

exit 0

fold

  将输入按照指定宽度进行折行. 这里有一个非常有用的选项 -s , 这个选项可以使用空格进行断行(事实上只有外文才需要使用空格断行, 中文是不需要的)

fmt

  一个简单的文件格式器, 通常用在管道中, 将一个比较长的文本行输出进行”折行”.

例:格式化文件列表.

#!/bin/bash
# fmt.sh

WIDTH=40                    # 设为40列宽.

b=`ls /home/liudezhi`       # 取得文件列表...

echo $b | fmt -w $WIDTH
# 与 echo $b | fold - -s -w $WIDTH相同.

exit 0

col

  这个命令用来滤除标准输入的反向换行符号. 这个工具还可以将空白用等价的tab来替换. col工具最主要的应用还是从特定的文本处理工具中过滤输出, 比如groff和tbl. (主要用来将man页转化为文本.)


column

  列格式化工具. 通过在合适的位置插入tab, 这个过滤工具会将列类型的文本转化为”易于打印”的表格式进行输出.


colrm

  列删除过滤器. 这个工具将会从文件中删除指定的列(列中的字符串)并且写到文件中, 如果指定的列不存在, 那么就回到 stdout . colrm 2 4 <filename 将会删除 filename 文件中每行的第2到第4列之间的所有字符.

  如果这个文件包含tab和不可打印字符, 那将会引起不可预期的行为. 在这种情况下, 应该通过管道的手段使用expand和unexpand来预处理colrm.


nl

  计算行号过滤器. nl filename 将会把 filename 文件的所有内容都输出到 stdout 上, 但是会在每个非空行的前面加上连续的行号. 如果没有 filename 参数, 那么就操作 stdin.

  nl命令的输出与 cat -n 非常相似, 然而, 默认情况下nl不会列出空行.

例:nl: 一个自己计算行号的脚本.

#!/bin/bash
# line-number.sh

# 这个脚本将会echo自身两次,并显示行号.

# 'nl'命令不计空行.
# 'cat -n'命令计空行.

nl `basename $0`

echo; echo

cat -n `basename $0`
# 'cat -n' 对空行也进行计数.
# 'nl -ba'也会这么做.

exit 0

pr
  格式化打印过滤器. 这个命令会将文件(或 stdout )分页, 将它们分成合适的小块以便于硬拷贝打印或者在屏幕上浏览. 使用这个命令的不同的参数可以完成好多任务, 比如对行和列的操作, 加入行, 设置页边, 计算行号, 添加页眉, 合并文件等等. pr命令集合了许多命令的功能, 比如nl, paste, fold,column, 和expand.

  pr -o 5 --width=65 fileZZZ | more 这个命令对fileZZZ进行了较好的分页,并且打印到屏幕上. 文件的缩进被设置为5,总宽度设置为65.

  -d 选项,强制隔行打印(与sed -G效果相同).


gettext

  GNU gettext包是专门用来将程序的输出翻译或者本地化为不同国家语言的工具集. 在最开始的时候仅仅支持C语言, 现在已经支持了相当数量的其它程序语言和脚本语言.


msgfmt

  一个产生二进制消息目录的程序.这个命令主要用来本地化.


iconv

  一个可以将文件转化为不同编码格式(字符集)的工具. 这个命令主要用来本地化.

# 将字符符串由UTF-8格式转换为UTF-16并且打印到BookList中
function write_utf8_string {
    STRING=$1
    BOOKLIST=$2
    echo -n "$STRING" | iconv -f UTF8 -t UTF16 | cut -b 3- | tr -d \\n >> "$BOOKLIST"
}

recode

  可以认为这个命令是上边iconv命令的专业版本. 这个非常灵活的并可以把整个文件都转换为不同编码格式的工具并不是Linux标准安装的一部分.


TeX, gs

  TeX和Postscript都是文本标记语言,用来对打印和格式化的视频显示进行预拷贝.

  TeX是Donald Knuth精心制作的排版系统. 通常情况下, 通过编写脚本的手段来把所有的选项和参数封装起来一起传到标记语言中是一件很方便的事情.

  Ghostscript (gs) 是一个 遵循GPL的Postscript解释器.


enscript

  将纯文本文件转换为PostScript的工具.

  比如,enscript filename.txt -p filename.ps 产生一个PostScript输出文件filename.ps.


groff, tbl, eqn

  另一种文本标记和显示格式化语言是groff. 这是一个对传统UNIX roff/troff显示和排版包的GNU增强版本. Man页 使用的就是groff.

  tbl表处理工具可以认为是groff的一部分, 它的功能就是将表标记转化到groff命令中.

  eqn等式处理工具也是groff的一部分, 它的功能是将等式标记转化到groff命令中.


lex, yacc

  lex是用于模式匹配的词汇分析产生程序. 在Linux系统上这个命令已经被flex取代了.

  yacc工具基于一系列的语法规范, 产生一个语法分析器. 在Linux系统上这个命令已经被bison取代了.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
通过抓取有道词典网页代码,截取想要的信息,格式化输出到命令行。搞定!对柯林斯英汉双解大词典的内容比较偏爱,所以我就截取了他的释义和例句。 #!/bin/bash ARGS=1 E_BADARGS=65 TEM_FILE="/tmp/dict.tmp" if [ $# -ne "$ARGS" ] then echo "Usage:`basename $0` word" exit $E_BADARGS fi # 抓取页面,删除html代码,空行等,只留下想要的内容 curl -s 'http://dict.youdao.com/search?q='$1'' | awk 'BEGIN{j=0;i=0;} {if(/phrsListTab/){i++;} if(i==1){print $0; if(/<\/ul>/){i=0;}} if(/collinsToggle/){ j++;} if(j==1) {print $0; if(/<\/ul>/){j=0;}}}' | sed 's/<[^>]*>//g' | sed 's/ //g'| sed 's/→//g' | sed 's/^\s*//g' | sed '/^$/d'> $TEM_FILE # 处理输出 is_head=true # 当前行是否属于“头部” head="" # 头部内容 body="" # 主体内容 ln_item=0 # 每一条解释的行号 ln_eg=0 # 例句行号 while read line do let ln_item++ let ln_eg++ num_flag=`echo "$line" | awk '/[0-9]+\.$/'` if [ "$num_flag" != "" ]; then ## 遇见'数字+点'开头的行 is_head=false # 第一次遇见数字行 将头部标示设置为false ln_item=0 fi eg_flag=`echo "$line" | awk '/例:$/'` # 遇见'例:'开头的行 if [ "$eg_flag" != "" ]; then ln_eg=0 fi if $is_head ; then head="$head $line" else if [ $ln_item == 0 ] ; then line="\033[32;1m\n\n$line\033[0m" # 释义编号 elif [ $ln_item == 1 ] ; then line="\033[32;1m[$line]\033[0m" # 词性 elif [ $ln_item == 2 ] ; then line="\033[1m$line\033[0m" # 释义 elif [ $ln_eg == 0 ] ; then line="\033[32;1m\n $line\033[0m" # 例: elif [ $ln_eg == 1 ]; then line="\033[33m$line\033[0m" # 例句 elif [ $ln_eg == 2 ]; then line="\033[33m$line\033[0m" # 例句释义 fi body="$body $line" fi done < $TEM_FILE echo -e "\033[31;1m$head\033[0m $body" exit 0

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值