如何使用 shell(awk、sed 等)删除文件中的前两列

Posted

技术标签:

【中文标题】如何使用 shell(awk、sed 等)删除文件中的前两列【英文标题】:how to remove the first two columns in a file using shell (awk, sed, whatever) 【发布时间】:2012-11-06 22:18:28 【问题描述】:

我有一个包含很多行的文件 在每一行中有许多列(字段),由空格“”分隔 每行的列数不同 我想删除前两列 怎么做?

【问题讨论】:

Using awk to print all columns from the nth to the last的可能重复 【参考方案1】:

使用 awk,并基于下面的一些选项,使用 for 循环会更灵活一些;有时我可能想删除前 9 列(例如,如果我执行“ls -lrt”),所以我将 2 更改为 9,就是这样:

awk ' for(i=0;i++<2;)$i=""; print $0 ' your_file.txt

【讨论】:

【参考方案2】:

使用kscript

kscript 'lines.split().select(-1,-2).print()' file

【讨论】:

【参考方案3】:

只用 shell 很简单

while read A B C; do
echo "$C"
done < oldfile >newfile

【讨论】:

这是一个很好的答案,但是您需要使用 read -r 而不是 read read -r 将保留反斜杠。 read 不会。例如:echo "foo ba\r" 将产生foo ba\r 的输出。但是,echo "foo ba\r" | (while read first_column second_column; do echo "$second_column"; done) 将仅生成bar 作为输出(删除了反斜杠。添加-r 标志会生成ba\r 的正确输出【参考方案4】:

perl:

perl -lane 'print join(' ',@F[2..$#F])' File

awk:

awk '$1=$2=""1' File

【讨论】:

【参考方案5】:

您可以使用cut

cut -d " " -f 3- input_filename > output_filename

说明:

cut:调用剪切命令 -d " ":使用单个空格作为分隔符(cut 默认使用 TAB) -f:指定要保留的字段 3-: 以字段 3 开头的所有字段 input_filename:使用这个文件作为输入 &gt; output_filename:将输出写入此文件。

或者,您可以使用awk

awk '$1=""; $2=""; sub("  ", " "); print' input_filename > output_filename

说明:

awk:调用 awk 命令 $1=""; $2="";:将字段 1 和 2 设置为空字符串 sub(...);:清理输出字段,因为字段 1 和 2 仍将由“”分隔 print: 打印修改后的行 input_filename &gt; output_filename:同上。

【讨论】:

@wenzi 哎呀,忘了cut 默认使用制表符作为分隔符。查看更新的答案 - 刚刚经过测试,它可以工作。在其他条件相同的情况下,我建议使用 cut 而不是 awk 您可以在 awk 中使用 awk 'sub(/([^ ]+ )2/, "")1'。我同意如果你有一个单字符字段分隔符,无论如何 cut 是更好的选择。 还有一些空格,请改用awk '$1=""; $2=""; sub(/^ +/, ""); print'或更短的awk '$1=$2=""; sub(/^ +/, "")1'【参考方案6】:

感谢您发布问题。我还想添加对我有帮助的脚本。

awk ' $1=""; print $0 ' file

【讨论】:

Awk 在这种情况下不保留字段分隔符。 可以加OFS=FS保留分隔符:unix.stackexchange.com/a/252748/112834【参考方案7】:

这是一种相对容易理解的使用 Awk 的方法:

awk 'print substr($0, index($0, $3))'

这是一个没有模式的简单 awk 命令,因此 内的操作针对每个输入行运行。

操作是简单地打印从第三个字段的位置开始的子字符串。

$0: 整个输入行 $3: 第三场 index(in, find):返回find在字符串in中的位置 substr(string, start):返回从索引 start 开始的子字符串

如果您想使用不同的分隔符,例如逗号,可以使用 -F 选项指定:

awk -F"," 'print substr($0, index($0, $3))'

您还可以通过在 中的操作之前指定模式来对输入行的子集进行操作。只有与模式匹配的行才会运行操作。

awk 'patternprint substr($0, index($0, $3))'

模式可以是这样的:

/abcdef/:使用正则表达式,默认对$0进行操作。 $1 ~ /abcdef/:对特定字段进行操作。 $1 == blabla:使用字符串比较 NR &gt; 1:使用记录/行号 NF &gt; 0:使用字段/列号

【讨论】:

谢谢你,这是一个比 IMO 接受的更好的答案 去掉最后两列怎么样,倒数? 如果字段 #2 和字段 #3 的内容相同,这将无法正常工作。【参考方案8】:

这可能对你有用(GNU sed):

sed -r 's/^([^ ]+ )2//' file

或者对于由一个或多个空格分隔的列:

sed -r 's/^(\S+\s+)2//' file

【讨论】:

【参考方案9】:

你可以使用sed:

sed 's/^[^ ][^ ]* [^ ][^ ]* //'

这会查找以一个或多个非空白、一个空白、另一组一个或多个非空白和另一个空白开头的行,并删除匹配的材料,即前两个字段。 [^ ][^ ]* 比等效但更明确的 [^ ]\1,\ 符号略短,第二个可能会遇到 GNU sed 的问题(尽管如果您使用 --posix 作为选项,即使 GNU sed 也不能搞砸了)。 OTOH,如果要重复的字符类更复杂,则编号符号会为简洁起见。很容易将其扩展为处理“空白或制表符”作为分隔符,或“多个空白”或“多个空白或制表符”。也可以对其进行修改以处理第一个字段之前的可选前导空格(或制表符)等。

对于awkcut,请参阅Sampson-Chen 的answer。还有其他方法可以编写awk 脚本,但它们并不比给出的答案更好。请注意,如果您不希望将制表符视为分隔符,或者字段之间可能有多个空格,则可能需要在 awk 中显式设置字段分隔符 (-F" ")。 POSIX 标准cut 不支持字段之间的多个分隔符; GNU cut 具有有用但非标准的 -i 选项,允许在字段之间使用多个分隔符。

你也可以在纯shell中做:

while read junk1 junk2 residue
do echo "$residue"
done < in-file > out-file

【讨论】:

如果residue 可以包含反斜杠,上面的读取将解释它,而不是在输出中重现它。始终使用while IFS= read -r ... 如果bash 用普通的read 解释内容,那么bash 被破坏(再次)。原始 shell 中的 read 命令没有做这种废话;我不相信 POSIX shell 需要它。如果发现bash 做了你所说的那样,我会很生气——我已经对这个程序产生了爱/恨的关系,因为它在很多事情上都做得很好,但也有一些事情做得很糟糕,并且改变遗留行为是最糟糕的行为之一,并且需要启用旧标准行为的选项是......非常烦人。看来你是对的; bash 很无聊! 这种行为是 POSIX,参见 pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html 我明白了,我没有明确说出来,但您需要 IFS= 的原因是,如果输入中的第一个字段为空,则默认字段拆分将去除前导空格,因此 residue 将开始在字段 4(或更高版本)而不是字段 3。 该死的...好的; POSIX 很糟糕,但 bash 正在追随 POSIX 2008。在超过 25 年的 shell 编程中,我从来没有想要这个功能,但我想我一定是少数。

以上是关于如何使用 shell(awk、sed 等)删除文件中的前两列的主要内容,如果未能解决你的问题,请参考以下文章

Shell 的sed和awk 工具

sed &amp;&amp; awk工具 及一些经常使用的shell脚本

sed && awk工具 及一些常用的shell脚本

三剑客之sed,awk,grep,egrep

shell中 sed或awk 把文件的两个字段调换位置

linux、 grep 、awk、sed 删除关键字的上一行