有没有办法使用 grep 或 egrep 格式化输出,并在输出实例之间使用分隔符?

有没有办法使用 grep 或 egrep 格式化输出,并在输出实例之间使用分隔符?

我有一个包含大量数据的数据集:

ID Number:  A00001
Name:       John Smith
Address:    123 Any Street
City:       AnyTown
State:      Ohio
Zip:        12345

ID Number:  A00002
Name:       Jane Doe
Address:    123 Any Street
City:       AnyTown
State:      Nebraska
Zip:        12346

ID Number:  C00003
Name:       Jim Shields
Address:    123 Any Street
City:       AnyTown
State:      Alaska
Zip:        12347

ID Number:  D11111
Name:       Mary Ellis
Address:    123 Any Street
City:       AnyTown
State:      Nevada
Zip:        12348

我想提取数据并将其分开,如下所示:

ID Number:  A00001
Name:       John Smith
Zip:        12345
=========================
ID Number:  A00002
Name:       Jane Doe
Zip:        12346
=========================
ID Number:  C00003
Name:       Jim Shields
Zip:        12347
=========================
ID Number:  D11111
Name:       Mary Ellis
Zip:        12348
=========================

我已经尝试了我能找到的每个 grep 和 egrep 选项,但我能得到的最接近的是在每行输出之间放置一个空行(新行)。

答案1

grep是一个模式匹配工具,而不是文本重新格式化工具。使用诸如sed, awk, 或 之类的东西perl代替。例如:

$ awk '/^(ID Number|Name|Zip):/;
       /^[[:blank:]]*$/ { print "=========================" }'
ID Number:  A00001
Name:       John Smith
Zip:        12345
=========================
ID Number:  A00002
Name:       Jane Doe
Zip:        12346
=========================
ID Number:  C00003
Name:       Jim Shields
Zip:        12347
=========================
ID Number:  D11111
Name:       Mary Ellis
Zip:        12348

[[:blank:]]*匹配任何行就像它们是空的,但实际上包含水平空间,例如空格或制表符......这比您想象的更常见,因为它是仅用您的眼睛很难看到的东西。

或者,使用 perl:

perl -l -n -e 'print if /^(ID Number|Name|Zip):/;
               print "=" x 25  if /^\h*$/' input.txt

或与sed.首先,如果您有 GNU sed 或其他一些能够理解 Perl RE 的\h“水平空间”的 sed:

sed -n -E -e '/^(ID Number|Name|Zip):/p; s/^\h*$/=========================/p' input.txt 

否则,使用任何 sed:

sed -n -E -e '/^(ID Number|Name|Zip):/p; s/^[[:blank:]]*$/=========================/p' input.txt

答案2

在每个 Unix 机器上的任何 shell 中使用任何 awk:

$ cat tst.awk
BEGIN {
    FS = ":"
    split(tgts,tmp)
    for (i in tmp) {
        tags[tmp[i]]
    }
    sep = "========================="
}
$1 in tags
!NF { print sep }
END { if (NF) print sep }

$ awk -v tgts='ID Number:Name:Zip' -f tst.awk file
ID Number:  A00001
Name:       John Smith
Zip:        12345
=========================
ID Number:  A00002
Name:       Jane Doe
Zip:        12346
=========================
ID Number:  C00003
Name:       Jim Shields
Zip:        12347
=========================
ID Number:  D11111
Name:       Mary Ellis
Zip:        12348
=========================

$ awk -v tgts='City:State' -f tst.awk file
City:       AnyTown
State:      Ohio
=========================
City:       AnyTown
State:      Nebraska
=========================
City:       AnyTown
State:      Alaska
=========================
City:       AnyTown
State:      Nevada
=========================

答案3

将每个部分视为一条记录,并将部分中的每一行视为一个字段,似乎您想要输出每个记录的前两个和最后一个字段,并用一行等号来分隔输出中的记录。

$ awk -F'\n' -v OFS='\n' -v RS='' -v ORS='\n=========================\n' '{ print $1,$2,$NF }' file
ID Number:  A00001
Name:       John Smith
Zip:        12345
=========================
ID Number:  A00002
Name:       Jane Doe
Zip:        12346
=========================
ID Number:  C00003
Name:       Jim Shields
Zip:        12347
=========================
ID Number:  D11111
Name:       Mary Ellis
Zip:        12348
=========================

命令行首先将输入和输出字段分隔符的值设置为换行符。这样做可以确保字段在输入和输出中都是单独的行。

然后将记录分隔符设置为空字符串,这将启用“段落模式”,即,它使我们能够将由一个或多个空行分隔的一段文本读取为单个记录。

然后将输出记录分隔符设置为等号,并在两端添加换行符。

实际代码打印每条记录的第一个、第二个和最后一个字段。您也可以使用$6代替$NF.

相关内容