O.E*_*O.E 13 command-line text-processing
我的文本文件如下所示:
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341
Run Code Online (Sandbox Code Playgroud)
现在我想Liquid penetration 95% mass (m)
从我的行中删除以仅获取值。我该怎么做?
Zan*_*nna 22
如果只有一个=
标志,您可以删除之前和包括的所有内容,=
如下所示:
$ sed -r 's/.* = (.*)/\1/' file
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
Run Code Online (Sandbox Code Playgroud)
如果要更改原始文件,请-i
在测试后使用该选项:
sed -ri 's/.* = (.*)/\1/' file
Run Code Online (Sandbox Code Playgroud)
-r
使用ERE所以我们没有逃避(
和)
s/old/new
替换old
为new
.*
任意数量的任意字符(things)
保存things
迟些反向引用\1
,\2
等等。hee*_*ayl 21
这是一份工作awk
;假设值仅出现在最后一个字段中(根据您的示例):
awk '{print $NF}' file.txt
Run Code Online (Sandbox Code Playgroud)
NF
是一个awk
变量,扩展为记录(行)中的字段数,因此$NF
(注意$
前面的)包含最后一个字段的值。例子:
% cat temp.txt
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341
% awk '{print $NF}' temp.txt
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
Run Code Online (Sandbox Code Playgroud)
pa4*_*080 15
我决定比较这里列出的不同解决方案。为此,我根据 OP 提供的内容创建了一个大文件:
我创建了一个简单的文件,名为input.file
:
$ cat input.file
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341
Run Code Online (Sandbox Code Playgroud)然后我执行了这个循环:
for i in {1..100}; do cat input.file | tee -a input.file; done
Run Code Online (Sandbox Code Playgroud)终端窗口被阻止。我killall tee
从另一个终端执行。然后我通过命令检查了文件的内容:less input.file
和cat input.file
。看起来不错,除了最后一行。所以我删除了最后一行并创建了一个备份副本:(cp input.file{,.copy}
因为使用inplace选项的命令)。
文件中的最终行数input.file
是2 192 473。我通过命令得到了那个号码wc
:
$ cat input.file | wc -l
2192473
Run Code Online (Sandbox Code Playgroud)这是比较的结果:
$ time grep -o '[^[:space:]]\+$' input.file > output.file 真正的 0m58.539s 用户 0m58.416s 系统 0m0.108s
$ time sed -ri 's/.* = (.*)/\1/' input.file 真正的 0m26.936s 用户 0m22.836s 系统 0m4.092s
或者,如果我们将输出重定向到新文件,命令会更快:
$ time sed -r 's/.* = (.*)/\1/' input.file > output.file 真正的 0m19.734s 用户 0m19.672s 系统 0m0.056s
gawk '{gsub(".*= ", "");print}'
$ time gawk '{gsub(".*= ", "");print}' input.file > output.file 真正的 0m5.644s 用户 0m5.568s 系统 0m0.072s
$ time rev input.file | 剪切 -d' ' -f1 | rev > output.file 真正的 0m3.703s 用户 0m2.108s 系统 0m4.916s
$ time grep -oP '.*= \K.*' input.file > output.file 真正的 0m3.328s 用户 0m3.252s 系统 0m0.072s
sed 's/.*= //'
(该-i
选项分别使命令慢了几倍)
$ time sed 's/.*= //' input.file > output.file 真正的 0m3.310s 用户 0m3.212s 系统 0m0.092s
perl -pe 's/.*= //'
(该-i
选项不会对此处的生产力产生太大影响)
$ time perl -i.bak -pe 's/.*= //' input.file 真正的 0m3.187s 用户 0m3.128s 系统 0m0.056s
$ time perl -pe 's/.*= //' input.file > output.file 真正的 0m3.138s 用户 0m3.036s 系统 0m0.100s
$ time awk '{print $NF}' input.file > output.file 真正的 0m1.251s 用户 0m1.164s 系统 0m0.084s
$ time cut -c 35- input.file > output.file 真实 0m0.352s 用户 0m0.284s 系统 0m0.064s
$ time cut -d= -f2 input.file > output.file 真实 0m0.328s 用户 0m0.260s 系统 0m0.064s
αғs*_*нιη 12
用grep
和-P
用于具有PCRE
(解读图案作为P ERL- Ç ompatible ř egular È XPRESSION)和-o
打印匹配的单独模式。该\K
通知会忽略自己之前所匹配的部分来了。
$ grep -oP '.*= \K.*' infile
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
Run Code Online (Sandbox Code Playgroud)
或者你可以改用cut
命令。
cut -d= -f2 infile
Run Code Online (Sandbox Code Playgroud)
Dav*_*ter 11
由于行前缀始终具有相同的长度(34 个字符),您可以使用cut
:
cut -c 35- < input.txt > output.txt
Run Code Online (Sandbox Code Playgroud)
小智 6
使用 反转文件的内容rev
,将输出通过管道传输到cut
以空格作为分隔符和 1 作为目标字段,然后再次反转以获取原始数字:
$ rev your_file | cut -d' ' -f1 | rev
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
Run Code Online (Sandbox Code Playgroud)
这很简单,简短,易于编写、理解和检查,我个人喜欢它:
grep -oE '\S+$' file
Run Code Online (Sandbox Code Playgroud)
grep
在 Ubuntu 中,当用-E
or调用时-P
,使用速记 \s
表示空白字符(实际上通常是空格或制表符)并\S
表示任何不是一个的东西。使用量词+
和行尾锚点$
,模式\S+$
匹配一行末尾的一个或多个非空白。您可以使用-P
代替-E
;这种情况下的含义是相同的,但使用了不同的正则表达式引擎,因此它们可能具有不同的性能特征。
这相当于Avinash Raj 的评论解决方案(只是使用更简单、更紧凑的语法):
grep -o '[^[:space:]]\+$' file
Run Code Online (Sandbox Code Playgroud)
如果数字后面可能有尾随空格,这些方法将不起作用。他们可以修改,所以他们这样做,但我认为在这里没有意义。尽管将解决方案概括为适用于更多情况有时是有益的,但像人们倾向于假设的那样经常这样做并不切实际,因为人们通常无法知道问题最终可能需要以多种不同的不兼容方式中的哪一种来解决被概括。
性能有时是一个重要的考虑因素。这个问题并没有规定输入非常大,很可能这里发布的每个方法都足够快。但是,如果需要速度,这里有一个关于一千万行输入文件的小基准:
$ perl -e 'print((<>) x 2000000)' file > bigfile
$ du -sh bigfile
439M bigfile
$ wc -l bigfile
10000000 bigfile
$ TIMEFORMAT=%R
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
819.565
$ time grep -oE '\S+$' bigfile > bigfile.out
816.910
$ time grep -oP '\S+$' bigfile > bigfile.out
67.465
$ time cut -d= -f2 bigfile > bigfile.out
3.902
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
815.183
$ time grep -oE '\S+$' bigfile > bigfile.out
824.546
$ time grep -oP '\S+$' bigfile > bigfile.out
68.692
$ time cut -d= -f2 bigfile > bigfile.out
4.135
Run Code Online (Sandbox Code Playgroud)
我运行了两次以防顺序很重要(因为它有时会处理 I/O 繁重的任务),并且因为我没有一台可用的机器在后台不做其他可能会扭曲结果的事情。从这些结果中,我得出以下结论,至少是暂时的,对于我使用的大小的输入文件:
哇!传递-P
(使用PCRE)而不是-G
(未指定方言时的默认值)或-E
使grep
速度提高一个数量级以上。所以对于大文件,使用这个命令可能比上面显示的更好:
grep -oP '\S+$' file
Run Code Online (Sandbox Code Playgroud)哇!!该cut
在方法?的???的答案,是在一个数量级,甚至比速度更快的版本我的方式更快!它也是pa4080 基准测试的赢家,它涵盖了比这更多的方法,但输入更少——这就是为什么我在所有其他方法中选择它来包含在我的测试中。如果性能很重要或文件很大,我认为应该使用??s??? 的方法。cut -d= -f2 file
cut
这也提醒我们不应忘记简单cut
和paste
实用程序,并且在适用时可能应该首选,即使有更复杂的工具grep
通常作为一线解决方案提供(而且我个人更习惯)使用)。