从文本文件中删除字符串的超集

从文本文件中删除字符串的超集

我有一个包含目录列表的文件:

/a/b
/a/b/c
/a/b/d /a/ b
/e
/a/c
/a/c/b
/a/c/d
/a/d/e
/a/d/e /f
/a/e/f/g /a/e/f/g
/h
...

我只想获取 /a/b、/a/c、/a/d/e 和 /a/e/f/g;也就是说,我想排除前面有另一行的子集的行。子目录的深度是任意的,因此我可以向下 2、3、4 等目录查找唯一的子目录。

答案1

假设您的输入已排序,那么检查前缀并在其更改时更新它怎么样?

$ awk 'NR == 1 || ! match($0, "^" pfx) {print; pfx = $0}' file
/a/b
/a/c

注意:这是正则表达式匹配,因此如果条目包含正则表达式特殊字符,则可能不合适 - FWIW 两者都没有gawkmawk似乎/在此上下文中将 视为特殊字符

答案2

gawk -F/ '
    {
        # have we seen something that is a prefix of this line?
        for (prefix in prefixes)
            if ($0 ~ "^" prefix)
                # yes we have
                next

        prefixes[$0] = 1

        # are there prefixes that get "cancelled out" by this new one?
        # e.g. /a/b/c is already a prefix but current line is /a/b
        for (prefix in prefixes)
            if (prefix ~ "^" $0 ".+")
                delete prefixes[prefix]
    }
    END {
        # GNU awk: traverse the array by index, sorted
        PROCINFO["sorted_in"] = "@ind_str_asc"
        for (p in prefixes)
            print p
    }
' list_of_dirs

输出

/a/b
/a/c
/a/d/e
/a/e/f/g

如果您没有 GNU awk,则将输出通过管道传输到| sort

答案3

$ awk -F/ 'NF==3 { print }' filename

我们将字段分隔符设置为/,然后打印仅包含三个字段的行。假设您的输入文件格式一致,则/a/b只会打印诸如 之类的行,因为这三个字段依次为空字符串、ab

答案4

您可以使用编辑器执行此操作,sed如下所示:

$ sed -e '
   $!N
   \|^\(.*\)\n\1/|!{P;D;}
   s/\n.*//;H;s/.*//;x;D
' input_file

/a/b
/a/c
/a/d/e
/a/e/f/g

在职的:

  1. 确保图案空间中随时有两条线。
  2. 如果在模式空间的第二部分的前导位置没有找到第一部分=>它们不属于同一分支。我们打印第一部分,将其删除,然后返回将下一行读入模式空间,并执行相同的检查。
  3. 在匹配的情况下,我们删除第二部分,因为这是较大的部分(由于排序输入假设),所以我们继续并立即删除该部分。然后返回并将下一行读入模式空间,然后冲洗/重复。

如果输入未排序,您可以按以下方式进行操作:

$ perl -lne '
    my $l = $_;
    grep !index($l,$_), keys %h or $h{$_}++;
    }{print for sort keys %h;
' input
/a/b
/a/c
/a/d/e
/a/e/f/g

在职的:

  • index(str, substr) 将返回在 str 中找到 substr 的索引。为了在开头匹配,返回 0,然后将其布尔值反转以使其读取为成功。 grep 将迭代哈希 %h 的所有当前键,其键是我们想要的子字符串。

相关内容