【问题标题】:How to remove items that show up as substring later in file?如何删除稍后在文件中显示为子字符串的项目?
【发布时间】:2020-08-31 19:27:34
【问题描述】:

给定一些文件,

foo/bar
foo/bar/gaz
foo/bar/urk
hello/world
hello/world/congress
hello/world/united/states
hello/world

如何删除之前的行作为子字符串的行?

例如,foo/bar/gazfoo/bar - 前一行 - 作为子字符串,应该被删除。

上面的列表应该简化为,

foo/bar
hello/world

(这有点像文件中行的公分母)

【问题讨论】:

  • foo/bar 是否会被视为bobfoo/barsue 的子字符串?
  • 您是否还想删除以下行作为子字符串的行?当最后一行是hello 时,是否应该删除hello/world

标签: shell unix awk sed


【解决方案1】:

您可以使用awk

awk '{for (i in a) if ($0 ~ i) next} {a[$0]}1' file

输出:

foo/bar
hello/world

【讨论】:

  • 好代码。我们确实以不同的方式解释了 OP 的目标。也许OP可以澄清。
  • @John1024 OP 说have previous lines as substrings。但是,是的,可能意味着AND starts with this substring 虽然还没有说过,但输入文件就是这样。第一种情况是第二种情况的超集,但是对于重要的情况(大输入),仅检查第二种情况可能会更快。无论如何,我们对修改持开放态度。好代码也是你的,干杯。
  • 如果我们只考虑开头的子字符串,修改条件为if ($0 ~ "^"i)
【解决方案2】:

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

sed -E 'G;/^([^\n]+).*\n\1(\n.*)*$/d;h;P;d' file

在保持空间中填充独特的行并删除部分/完全匹配这些行的行。

【讨论】:

    【解决方案3】:

    试试:

    $ awk '{for (s in a) if (s == substr($0,1,length(s))) next; print; a[$0]}' file
    foo/bar
    hello/world
    

    前面的行,不包括其他行的子字符串,是数组a的键。 for (s in a) if (s == substr($0,1,length(s))) next 检查当前行 $0 是否是前一行的子字符串。如果是这样,我们跳过这行并跳转到next 行。

    如果当前行不是上一行的子字符串,那么我们print它并将其添加为a的键。

    另一个例子

    $ cat file2
    /etc
    /foo/bar/etc
    $ awk '{for (s in a) if (s == substr($0,1,length(s))) next; print; a[$0]}' file2
    /etc
    /foo/bar/etc
    

    此答案中的代码将“公分母”视为从字符串的开头开始。因此,/etc 不是 /foo/bar/etc 的“公分母”,即使两者都有共同的子字符串 /etc

    【讨论】:

      【解决方案4】:

      当您有一行foo/bar 时,您想删除带有foo/bar. 的所有内容。
      只需在每一行添加一个点并将其用于排除列表。

      grep -vf <(sed 's/$/./' file) file
      

      【讨论】:

        【解决方案5】:

        这是一个awk,如果您的文件较大,它可能会更快:

        awk 'BEGIN { FS=OFS="/" } 
                        $0 in arr { next }
                        {   s=$1
                            for (i=2; i<=NF; i++) {
                                if (s in arr || (s OFS $i) in arr) next
                                s=s OFS $i}
                            arr[$0]} 1' file
        

        不是循环输入每一行的整个数组内容,而是循环每一行的子字符串并测试它是否存在于先前子字符串的数组中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-27
          • 1970-01-01
          • 2018-12-06
          相关资源
          最近更新 更多