【问题标题】:delete lines if $4 is one如果 $4 为 1,则删除行
【发布时间】:2013-01-27 23:33:29
【问题描述】:

如果 $4 是 1,我想从文本文件中删除行

123  34  A   0
23   45  A   1  
36   5   A   36
176  3   A   1

想要的输出

123  34  A   0
36   5   A   36

我需要就地编辑。如何使用 awk 或 sed 执行此操作?

【问题讨论】:

    标签: sed awk


    【解决方案1】:

    awk:

    awk '$4 != 1'
    

    sed 中是可行的,但要困难得多,我不会打扰:

    sed '/^[^ ][^ ]*  *[^ ][^ ]*  *[^ ][^ ]*  *1 *$/d'
    

    或者,如果你有 GNU sed

    sed -r '/^[^ ]+ +[^ ]+ +[^ ]+ +1 *$/d'
    

    【讨论】:

    • +1 用于 awk 解决方案。很难相信人们会更喜欢复杂的 sed 解决方案来进行就地编辑而不是简单的awk file > tmp && mv tmp file,但幸运的是,即将发布的 gawk 版本将支持就地编辑,这样我们就可以停止这种疯狂......
    • @EdMorton:虽然我个人更喜欢 Perl 解决方案,但我几乎不会说它复杂。无论哪种方式,当以 root 身份运行时,就地编辑更加方便,这可能是 OP 需要它的原因。只是一个猜测。重头条新闻,我等不及了:-)
    • @steve - 好吧,您将 perl 代码称为“更具可读性”,而 Jonathan 将 sed 代码称为“我不会打扰”,这两个听起来都像只是另一种说法,sed 代码很复杂,但我想是 YMMV。当您说“以root身份运行时就地编辑更方便”时,您是什么意思? sed 只是在幕后使用了一个 tmp 文件,所以它不像真的在原地编辑文件,所以我不明白为什么以 root 身份登录应该与权限或任何东西有关。
    • @EdMorton:我的意思是sudo sed -i '...'sudo sh -c "awk '...' a > b && mv b a" 相比看起来更干净一些,虽然是的,但效果最终是相同的。处理 awk 内部的任何引用是我开始发现的不便之处,尤其是在有大量 print 和 printf 语句时。
    • @steve:如果你可以写sudo sed -i '...',为什么不写sudo awk '...' 避免sh -c "..." 的复杂性?
    【解决方案2】:

    一种使用GNU sed-i 就地编辑和-r 扩展正则表达式的方法:

    sed -ri '/^\S+\s+\S+\s+\S+\s+1( |$)/d' file
    

    如果您迫切需要就地编辑,您可能还想尝试perl 的自动拆分功能。该代码也更具可读性和可移植性:

    perl -i -ane 'print if $F[3] != 1' file
    

    结果:

    123  34  A   0
    36   5   A   36
    

    【讨论】:

    • 您确定\S\s 符号吗?它们来自 PCRE,但Regular ExpressionsExtended Regular Expressions 上的 GNU sed 手册页没有提及这些符号。会不会有文档错误?
    • @JonathanLeffler:是的。我一直认为\S\s 是ERE(和PCRE)。我也认为更多的文档是一件好事。
    • 我刚刚从 2012 年 12 月开始检查 GNU sed 4.2.2,它不支持 \s\S 符号,并且您建议的 sed 命令不起作用,因此.
    • @JonathanLeffler:您完全确定您使用的是您所说的sed 版本吗?我相信你可能把你的安装搞混了。我可以确认给定的命令将与 GNU sed version 4.2.1 一起使用,它早于你的日期 - 我非常怀疑对 \S\s 的支持会被贬低。那将是愚蠢的。该符号实际上是标准的(作为 ERE),我之前已经看过很多像 this 这样的答案。
    • 我刚刚重试了——看来我昨晚犯了一个错误。我不确定我做错了什么。我又看了一下 GNU 文档。序列反斜杠-s 和反斜杠-S 没有出现在其中。 POSIX RE(BRE 和 ERE)符号中也没有记录。
    【解决方案3】:

    只是为了与众不同……

    $ ed << \eof
    g- 1$-d
    w
    q
    eof
    

    【讨论】:

    • 假设正好有四个字段并且没有尾随空格;这对现有的样本数据有好处,但不一定适用于所有其他数据。当然,很难做到一概而论。
    【解决方案4】:

    使用 awk

    awk '{if($4 != 1 ) print $0}' temp.txt

    【讨论】:

    • 这与 Jonathan 6 小时前的回答有何不同?
    • @steve 那是简短的形式。我总是尝试不使用快捷方式进行写作。新用户很容易看到发生了什么。从 awks 的角度来看,以前的解决方案看起来小而好的解决方案,但我是一个新用户,请尝试我以完整的方式编写,以便 awk 的新手可以看到 if 是条件等。我还尝试查看经验较少的用户的解决方案,因为这对我来说更有意义,因为他通常以不太紧凑的形式编写,易于理解。但是对于更有经验的用户,他们会用一些难以掌握的字符来编写
    • 你提出的最后一点是有争议的。无论如何,如果您想表达自己的观点,我更愿意将您的解决方案视为乔纳森回答下的评论,而不是作为答案本身。请记住,SO 是一个问答网站,而不是某种论坛。而且我敢肯定,如果他/她不理解代码或想要更多解释,OP 会询问回答者。
    • @steve ,实际上我没想过在评论中添加它,但我下次会注意的。但是我已经看到 50% 的时间如果解决方案有效,那么 OP 只是在不理解的情况下复制粘贴它。我已经看到许多解决方案被接受,但新用户没有 cmets。我不得不做一些研究来理解那些是什么意思。即使我不得不请人解释。我想我已经用你的回答做了很多次了:)
    • 如果我要不使用缩写形式,我会使用:awk '$4 != 1 { print $0 }',使用awk 支持的显式模式动作表示法。你有一切行动;我的回答很有规律;这里的版本既有模式又有动作。 $0 当然是可选的;一个普通的print 无论如何都会打印$0
    猜你喜欢
    • 2019-01-12
    • 2016-02-05
    • 1970-01-01
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    相关资源
    最近更新 更多