这与问题" 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 ......)。 (重新排序很好。)
答案 0 :(得分:4)
使用awk:
awk '{if(k && match($0, k))next; k="^"$0}1' file
k =" ^" $ 0将模式锚定到字符串的开头。
如果有EMPTY行,可能需要在主块之前NF>0
。
更新:如果变量k
中存在正则表达式元字符可能会出现问题,不使用正则表达式的下一行应该更好:
awk '{if(k && index($0, k)==1)next; k=$0}1' file
更新-2:感谢@Ed,我已经调整了第二种方法来覆盖评估为零的非空行(尽管空行将保持原样):< / p>
awk '{if(k!="" && index($0,k)==1)next;k=$0}1' file
答案 1 :(得分:2)
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/
答案 2 :(得分:1)
Perl 1-liner。循环输入行-n
,然后执行-e
以下程序,检查当前行的开头是否与最后一行匹配,打印不匹配。
perl -ne 'print unless m|^$last|; chomp($last=$_);' file_list.txt
答案 3 :(得分:1)
$ awk 'NR==1 || index($0,prev)!=1{prev=$0; print}' file
a/
bar/foo/
bar/foo2/
c/d/