【问题标题】:Remove line (omit from the output) if the previous line is a prefix如果前一行是前缀,则删除行(从输出中省略)
【发布时间】:2018-05-27 23:54:25
【问题描述】:

这与问题“remove duplicate lines with similar prefix”非常相似,但反过来:

给定一个 排序 字符串(在本例中为目录)的输入,例如:

a/
a/b/c/
a/d/
bar/foo/
bar/foo2/
c/d/
c/d/e/

我想从输出中删除行,如果前一行是当前行的前缀。在这种情况下,输出将是:

a/
bar/foo/
bar/foo2/
c/d/

这在 Python 等中很容易编写代码,但在这种情况下,我处于 ​​shell 环境中(bash、sort、sed、awk...)。 (重新排序就可以了。)

【问题讨论】:

  • a/b/c/a/d/ 的前缀吗?
  • 由于a/ 存在a/d/ 不应存在于输出中。

标签: bash awk


【解决方案1】:

使用 awk:

awk '{if(k && match($0, k))next; k="^"$0}1' file

k="^"$0 将模式锚定到字符串的开头。

可能在主块之前需要NF>0,以防有空行。

更新:如果变量k 中存在正则表达式元字符可能会出现问题,以下行不使用正则表达式会更好:

awk '{if(k && index($0, k)==1)next; k=$0}1' file

Update-2:感谢@Ed,我已调整第二种方法以覆盖评估为零的非空行(空行将保持原样):

awk '{if(k!="" && index($0,k)==1)next;k=$0}1' file

【讨论】:

  • @EdMorton,很好的追赶,当行为零或空时,第二个确实有问题。由于前缀为^,第一个应该没问题。
【解决方案2】:

Perl 1-liner。循环输入行-n,然后执行-e以下程序,检查当前行的开头是否与最后一行匹配,打印不匹配的。

perl -ne 'print unless m|^$last|; chomp($last=$_);' file_list.txt

【讨论】:

    【解决方案3】:

    Bash 本身(实际上是 POSIX shell)通过 带有子字符串删除的参数扩展提供了您所需要的一切。您需要做的就是检查您读取的行是否与删除了前缀的行匹配。如果没有,则您有一个前缀行,否则,您有一个非前缀行。然后输出无前缀行并将前缀设置为当前行是一件简单的事情——然后重复,例如

    #!/bin/bash
    
    pfx=    ## prefix
    
    ## read each line
    while read -r line; do 
        ## if no prefix or line matches line with prefix removed
        if [ -z "$pfx" -o "$line" = "${line#$pfx}" ]
        then
            printf "%s\n" "$line"   ## output lile
            pfx="$line"             ## set prefix to line
        fi
    done < "$1"
    

    (注意:如果输入文件有可能不包含 POSIX 文件结尾,例如文件最后一行的 '\n',那么您应该检查行的内容作为while 的条件,例如while read -r line || [ -n "$line" ]; do ...)

    输入文件示例

    $ cat string.txt
    a/
    a/b/c/
    a/d/
    bar/foo/
    bar/foo2/
    c/d/
    c/d/e/
    

    使用/输出示例

    $ bash nonprefix.sh string.txt
    a/
    bar/foo/
    bar/foo2/
    c/d/
    

    【讨论】:

      【解决方案4】:
      $ awk 'NR==1 || index($0,prev)!=1{prev=$0; print}' file
      a/
      bar/foo/
      bar/foo2/
      c/d/
      

      【讨论】:

      • 如果第一行为 EMPTY,则此行将无法生存
      • 我明白你在说什么,但我们不知道这是否会正确运行,因为如果前一行为空,OP 没有告诉我们正确的行为是什么。换句话说,它是未定义的行为,因此工具所做的任何事情都是合规/正确的:-)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-08
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      相关资源
      最近更新 更多