shell中文本处理的基本方式

2021-06-14

关键字:


1、echo

echo是shell中最常用的文本输出命令。其基本语法如下所示:

echo [option] string...

echo命令可用的 option 如下表所示:

option 释义
-E 默认选项,当echo不携带任何选项时即相当于带上了此选项。此选项表示不解析string中的转义字符。
-e 与 -E 相对,使用此选项后即表示会解析string中的转义字符。
-n 在输出完string后不追加一个换行字符。

 

另外,echo命令支持的转义字符如下表示所:

转义字符 含义
\a 报警符。相当于ASCII中的BEL字符。
\b 退格符。输出此转义字符会将已输出的一个字符“吃掉”。
\c 禁止继续输出文本。输出此转义字符后,同一条echo命令后面要输出的文本均不会再执行。
\f 换页符
\n 换行符
\r 回车符
\t 水平制表符
\v 垂直制表符
\\ 输出一个反斜线

 

echo 命令默认将文本输出到控制台,即作为打印信息显示在屏幕上。可以使用重定向符将文本流往文件系统输出。具体如下所示:

#!/bin/bash

#将文本保存到 /var/file1 文件中去
echo "hello world" > /var/file1

#将文本追加到 /var/file1 文件中去
echo "hello rust" >> /var/file1

 

下面结合echo命令的选项及转义字符编写一个 0% ~ 100% 的进度条显示shell函数。该函数不同于传统的echo输出命令会为每一个新值开辟一个新行,而是在数值更新时直接将旧值更新为新值。就类似于日常手机或网页中的百分比进度条那种效果。这个shell函数的核心思想就是使用 \b 退格转义字符,在百分比值更新时将已输出在屏幕上的旧值“吃掉”,然后再填充以新值从而达到我们想要的效果。

 

以下是完整的源码:

#!/bin/bash

#定义打印百分比值的函数
function progress ()
{
    #参数检查,调用此函数时必须传递一个参数
    if [ $# -ne 1 ]; then
        echo "Usage:"
        echo "  progress [percentage]"
        echo "eg:"
        echo "  progress 0"
        echo "  progress 100"
        return 1
    fi
    
    #参数类型检查,传递进来的参数必须是 0 ~ 100 之间的整数
    local progress_ttmp_1=1
    if [ $1 -ge 0 2> /dev/null -a $1 -le 100 2> /dev/null ]; then
        progress_ttmp_1=0
    fi
    
    if [ $progress_ttmp_1 -ne 0 ]; then
        echo "Can only accept integer parameter"
        return 2
    fi

    #百分比值更新。progress_ttmp_2 变量纯粹是为了标识是否第一次调用此函数。这关系到如何输出\b字符
    if [ "$progress_ttmp_2" = "1" ]; then
        #控制好\b字符的输出数量从而保证输出格式不出错。
        if [ $1 -le 10 ]; then
            echo -ne "\b\b$1%"
        else
            echo -ne "\b\b\b$1%"
        fi
    else
        progress_ttmp_2="1"
        #首次调用函数,无须输出\b转义字符
        echo -n "$1%"
    fi
}


#模拟一个从 0 ~ 100 的进度状态流程
for (( i=0; i<101; i++ ))
do
    progress $i
    #当函数成功执行时延时10毫秒来模拟后台作业耗时
    if [ $? -eq 0 ]; then
        sleep 0.01
    else
        #进度打印出错时直接退出
        break
    fi
done

 

 

2、fold

fold命令的功能是将超过指定宽度的文本行强制做换行处理。其语法如下所示:

fold [option] [file]...

fold 命令可以同时处理多个文件,不同文件之间以空格字符隔开。

 

option的可选值如下表所示:

选项 含义
-b 按字节计算宽度。超过-w选项指定的字节数时为此行做换行处理。默认情况下按列数计算(按字符)。
-s 在空格处做换行操作以避免单词被折断。
-w 指定行宽度上限。超过此选项指定的宽度值时自动为此行做换行处理。默认的宽度是80列后换行。

具体的使用示例如下所示:

fold -w 55 story.txt
fold -s -w 86 story.txt
fold -b story.txt
fold -b -w 100 story.txt

 

 

3、fmt

与fold命令类似,fmt命令的功能也是将超过指定宽度的文本行强制换行。但是fmt的功能会多于fold命令。其语法如下所示:

fmt [-width] [option] [file]

-width参数用于指定文本行的列数,默认为75列,即75个字符后换行。

 

此命令同样可以同时处理多个文件,不同文件之间以空格隔开。

 

option的可选值如下表所示:

选项 含义
-c 保留每个段落的前两行的缩进。
-t 与-c选项功能类似,但是在使用此选项时,每个段落的第1行和第2行的缩进必须是不相同的,否则第1行被看做一个单独的段落。
-s 只折断超出指定宽度的行,不合并少于指定宽度的行。默认情况下是会合并少于指定宽度的行的。
-u 统一空格数量,单词之间保留1个空格,句子之间保留2个空格。
-w 指定每个行的最大宽度,默认为75列。

 

以下是具体的示例程序:

fmt -c -w 80 story.txt
fmt -s -c -w 80 story.txt
fmt -20 -s story.txt

 

 

4、rev

rev命令的作用是反转字符顺序。即将文本中每一行的字符倒转过来。语法如下所示:

rev [file]...

多个文件之间以空格字符隔开。

 

使用示例如下所示:

rev story.txt

 

 

5、文本统计

1、输出带有行号的文本

可以使用 cat 命令带参数,如下所示:

cat -n story.txt

将输出的流重定向至文件中即可完成格式化修改。

 

除此之外,nl 命令也可为文件流带上行号。其语法如下所示:

nl [option] [file]

nl命令支持的option较多,常用的几个则如下表所示:

option 含义
-b 显示风格控制。可取 a , t , n 作为值。a表示为所有行添加行号。t表示仅为非空行添加行号(默认)。n表示不添加行号。
-i 行号的增量,默认为1。
-v 行号的起始值,默认为1。

使用示例如下所示:

nl story.txt
nl -b a story.txt

 

 

2、统计行数

使用 grep 命令加 -c 选项可以统计符合条件的结果行数。其示例代码如下:

grep -c "keyword" story.txt

 

另外,还有一个更专业的统计文本专用的命令:wc。

 

wc命令即 word count 的缩写。其语法如下所示:

wc [option] [file]

option可用的值如下表所示:

option 含义
-c 统计文本的字节数。
-m 统计字符数。
-l 统计行数。
-L 统计最长的文本行的长度。
-w 统计单词数。

具体示例如下所示:

wc -m story.txt
wc -l story.txt

直接使用wc命令统计文件中文本的数据时会在统计结果末尾显示出被统计文件名。如果不想显示此文件名,可以配合cat和管线命令来去除,具体用法如下所示:

cat story.txt | wc -m
cat story.txt | wc -l

 

  

6、cut

cut命令的作用是将文本中的数据按指定分隔符提取若干文本列。其语法如下所示:

cat [option] [file]

常用的option值如下表所示:

option 含义
-b 只选择指定的字节。
-c 只选择指定的字符。
-d 自定义列分隔符,默认为制表符。
-f 只选择列表中指定的文本列。文本列号从1开始,多个列之间以逗号隔开,连续列以减号代替。
-n 取消分隔多字节字符
-s 不输出不包含列分隔符的行。

具体示例如下所示:

cut -d ":" -f 1,7 /etc/passwd

表示将 /etc/passwd 文件以 ":" 作为分隔符,提取其第1列与第7列的数据。

cut -d ":" -f 1-4 /etc/passwd

功能同上,这次提取的是第1 ~ 第4列的数据。

cut -d ":" -f 3- /etc/passwd

功能同上,这次提取的是第3列及以后的数据。

cut -d ":" -f 1,2,4-7 /etc/passwd

功能类似于上面几条。

 

可以不指定分隔符只提取文本中指定列号处的字符数据:

cut -c 1,3,5 /etc/passwd

 

 

7、paste

paste命令与cut命令是相对的一组命令,它负责将多个文件中的内容合并起来。其语法如下所示:

paste [option] [file]

option常用的值如下表所示:

option 含义
-d 指定拼接结果中列分隔符。默认使用制表符分隔。
-s 将多个文件串行拼接,即后面的文件内容以追加的方式添加到前一个文件内容中。

具体示例如下所示:

paste story.txt author.txt > book_info.txt

paste命令本身不支持选列拼接,但是可以通过与cut命令配合来达到此效果,示例如下:

cut -f 1,2 phones.txt > phones.tmp
cut -f 2 authors.txt > authores.tmp
paste authores.tmp phones.tmp > contacts.txt

 

 

8、tr

tr 命令是 translate 的缩写。其功能是批量替换文本中的字符。语法如下:

tr [option] [set1] [set2]

option常用的值如下表所示:

option 含义
-c 用字符集set2替换字符集set1中没有包含的字符。
-d 删除字符集set1中的所有字符,不执行替换操作。此时无须传入set2参数。
-s 压缩set1中重复的字符。
-t 将字符集set1用set2转换。

 

如想去掉文本中所有的空行:

cat story.txt | tr -s ["\n"]

 

删除指定字符:

tr -d [rust] < story.txt

此举,会将 story.txt 中所有的字母 r , u , s, t 删除掉。

 

个人认为,tr命令特别不实用。

 


 

上一篇:C++学习笔记(Day16 排序 查找)


下一篇:Day16:高级特性