【问题标题】:delete a column with awk or sed使用 awk 或 sed 删除列
【发布时间】:2013-02-27 23:45:31
【问题描述】:

我有一个包含三列的文件。我想删除第三列(就地编辑)。如何使用 awk 或 sed 做到这一点?

123   abc  22.3
453   abg  56.7
1236  hjg  2.3

期望的输出

123  abc
453  abg
1236 hjg 

【问题讨论】:

  • 我很困惑:我开了一个赏金来推广 Ed Morton 的答案,到目前为止,the most upvotes 在这些天的帖子一直是问题,它没有显示任何研究 (@_@)

标签: sed awk


【解决方案1】:

看来你可以简单地选择

awk '{print $1 " " $2}' file

这会打印输入文件中每一行的前两个字段,用空格分隔。

【讨论】:

  • 这假定只有 3 列。否则,您将需要一个循环:awk '{printf $1 OFS $2; for(i=4;i<=NF;i++) printf OFS $i; printf ORS}' file(OFS 默认为空格,ORS 默认为换行符)。
【解决方案2】:

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

sed -i -r 's/\S+//3' file

如果要删除第三个字段之前的空白:

sed -i -r 's/(\s+)?\S+//3' file

【讨论】:

  • @potong, 是\S 的意思是所有不是空格的字符 吗?它记录在哪里?
  • -r 是做什么的?我的 sed 没有。
  • @JoshuaCheek -r 是启用 ERE 的 GNU sed 特定选项(google that)。如果您使用-E 而不是-r,它将在 GNU sed 以及其他一些 sed 中工作。
  • @GillesQuenot 是的,完全正确。您可以在regular expression extensions 部分的 GNU 手册中看到它。
  • 这仅适用于我的 GNU sed 的第一行
【解决方案3】:

试试这个:

awk '$3="";1' file.txt > new_file && mv new_file file.txt

awk '{$3="";print}' file.txt > new_file && mv new_file file.txt

【讨论】:

    【解决方案4】:

    试试这个简短的东西:

    awk '!($3="")' file
    

    【讨论】:

    • 这实际上并没有删除给定的列;它将它设置为空字符串,但您仍然会在输出中获得额外的FS。这可能很重要,也可能不重要,具体取决于您对转换后的数据所做的工作。
    • 试试这个将生成的输出保存到一个新文件。 awk '!($3="")' 文件 > 新文件
    • @A.Danischewski 这不是个好办法,如果 awk 脚本有错误怎么办?你丢失了你的文件。拿着这个awk '..' file > tmp && mv tmp file
    • @A.Danischewski 还有其他可能影响的情况:如果文件系统有空间问题怎么办?
    • 这也将重新编译当前记录,用单个空白字符替换字段之间的所有空格,并删除任何前导和/或尾随空格。鉴于他发布的输入,它不会产生 OP 所需的输出。为此,您需要stackoverflow.com/a/38145415/1745001
    【解决方案5】:

    使用 GNU awk 进行就地编辑,\s/\Sgensub() 用于删除

    1) FIRST 字段:

    awk -i inplace '{sub(/^\S+\s*/,"")}1' file
    

    awk -i inplace '{$0=gensub(/^\S+\s*/,"",1)}1' file
    

    2) LAST 字段:

    awk -i inplace '{sub(/\s*\S+$/,"")}1' file
    

    awk -i inplace '{$0=gensub(/\s*\S+$/,"",1)}1' file
    

    3) 第 Nth 字段,其中 N=3:

    awk -i inplace '{$0=gensub(/\s*\S+/,"",3)}1' file
    

    如果没有 GNU awk,您需要一个 match()+substr() 组合或多个 sub()s + vars 来删除中间字段。另见Print all but the first three columns

    【讨论】:

    • 注意:在 Ubuntu Trusty GNU Awk 4.0.1 上默认没有启用 awk 就地扩展。
    • 我认为您的意思是 /\s+\S+/ 带有 s+ 而不是 /\s*\S+/
    • @BrianWiley 否,因为如果前面没有空格,它将不适用于第一个字段。
    【解决方案6】:

    尝试使用 cut...它又快又简单

    首先你有重复的空格,如果你想要tr -s ' ',你可以将它们压缩到列之间的单个空格

    如果每一列之间已经只有一个分隔符,您可以使用cut -d ' ' -f-2 打印字段(列)

    例如,如果您的数据在文件 input.txt 中,您可以执行以下操作之一:

    cat input.txt | tr -s ' ' | cut -d ' ' -f-2
    

    或者,如果您通过删除第 3 列来更好地解释这个问题,您可以编写以下内容

    cat input.txt | tr -s ' ' | cut -d ' ' --complement -f3
    

    cut 非常强大,除了列之外,您还可以提取字节或字符范围

    摘自手册页关于如何指定列表范围的语法

    Each LIST is made up of one range, or many ranges separated by commas.
    Selected input is written in the same order that it is read, and is
    written exactly once. Each range is one of:
    
      N     N'th byte, character or field, counted from 1
      N-    from N'th byte, character or field, to end of line
      N-M   from N'th to M'th (included) byte, character or field
      -M    from first to M'th (included) byte, character or field
    

    所以你也可以说你想要特定的第 1 列和第 2 列...

    cat input.txt | tr -s ' ' | cut -d ' ' -f1,2
    

    【讨论】:

    • 我知道这不是问题的答案,但它肯定是最好的答案!
    • 同意,其余的答案处理空格,如果您在制表符分隔的文件的列中有空格,则空格将不起作用。这适用于制表符分隔的cut -f1-241,243-267,269-278 -d$'\t',它将删除第 242 和 268 列。
    【解决方案7】:

    如果您愿意接受 Perl 解决方案...

    perl -ane 'print "$F[0] $F[1]\n"' file
    

    使用以下命令行选项:

    • -n 循环输入文件的每一行,不要自动打印每一行

    • -a 自动拆分模式 - 将输入行拆分为 @F 数组。默认为空格分割

    • -e执行下面的perl代码

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-21
      • 2020-04-25
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 2019-09-12
      相关资源
      最近更新 更多