ソートされたパスのリストを含むテキストファイルがある場合は、その親パス(直接かどうかにかかわらず)もリストにあるため、重複するすべてのパスを削除するにはどうすればよいですか?
たとえば、
/aaa/bbb
/aaa/bbb/ccc
/ddd/eee
/fff/ggg
/fff/ggg/hhh/iii
/jjj/kkk/lll/mmm
/jjj/kkk/lll/mmm/nnn
次のように減らす必要があります。
/aaa/bbb
/ddd/eee
/fff/ggg
/jjj/kkk/lll/mmm
私はawkで部分文字列を試しましたが、親パスが毎回同じレベルになることを保証できないため、正しく機能できません。
答え1
私はこれが可能でなければならないと思います。追加のケースを追加するには、入力ファイルを編集してください。
$ cat ip.txt
/aaa/bbb
/aaa/bbbd
/aaa/bbb/ccc
/ddd/eee
/fff/ggg
/fff/ggg/hhh/iii
/jjj/kkk/lll/mmm
/jjj/kkk/lll/mmm/nnn
/jjj/kkk/xyz
使用awk
$ awk '{for (i in paths){if (index($0,i"/")==1) next} print; paths[$0]}' ip.txt
/aaa/bbb
/aaa/bbbd
/ddd/eee
/fff/ggg
/jjj/kkk/lll/mmm
/jjj/kkk/xyz
paths[$0]
入力行によってキーが割り当てられた参照です。for (i in paths)
各行は、保存されたすべてのキーと比較されます。if (index($0,i"/")==1) next
/
行の先頭に追加された保存キーと一致する場合は、入力行をスキップします。/
/aaa/bbbd
マッチングを避けるために使用/aaa/bbb
答え2
そして強制sed
ソリューションは次のとおりです。
sed '1s/^/#/;x;G;\_#\([^#]*\)#.*\n\1/_s/\n.*//;s/\n\(.*\)/\1#/;h;$! d;x;s/^#//;s/#$//;y/#/\n/'
このスクリプトは予約済みスペースからパスを収集します。新しい行ごとに予約されたスペースがパターンスペースに追加されているかどうかを確認します。
このソリューションでは、#
その文字がファイルに使用されていないと想定しています。それ以外の場合は別の文字を使用するか、GNUを使用している場合はsed
投稿の下部にある短いバージョンを使用してください。
上海:
1s/^/#/
移植性のために予約され#
たスペースでパスを区切るために文字が使用されます。最初の行の場合は、最初から始める必要があります。#
x;G
By exchanging the spaces and appending the hold space, we have the list of already occured buffers first, then the new path.
\_#\([^#]*\)#.*\n\1/_s/\n.*//
アドレスが一致すると、\_..._
新しいパスは古いパスのサブパスであるため削除されます。
s/\n\(.*\)/\1#/
それでもスペースに改行があるので、パスは新しいパスなので、リストに追加します。
h;$! d
最後の行でない場合は、新しいリストを予約済みスペースに保存して再起動してください。
x;s/^#//;s/#$//;y/#/\n/
最後の行の先頭と終了の内容を削除し、#
他の内容を改行に置き換えます。#
GNUの代替sed
sed
順序が復元されても問題ない場合は、GNU拡張を使用してこれを簡単に実行できます。
sed 'G;\_^\([^\n]*\)/.*\n\1\n_s/[^\n]*\n//;h;$! d;x;s/^\n//;s/\n$//'
上記のように説明しましたが#
。
答え3
このような:
$ awk '{sub(/\/$/, "")}
NR != 1 && substr($0, 0, length(prev)) == prev {next};
{print; prev = $0"/" } ' paths
最初の(NR != 1
)を除くすべての行で、その行の接頭辞を保存された行prev
(長さと同じ文字prev
)と比較します。一致すると、next
その行に移動します。それ以外の場合は、print
出力して行をに保存しますprev
。
ファイルがCロケールでソートされていると仮定すると(/
文字の前など)、またはディレクトリツリーナビゲーションで作成された場合は、以前に保存された行をテストするだけで十分です。ファイルが別のロケールでソートされていると、ソート/
に影響を与えず、などのソートが発生する可能性があり/aaa/bbb
ます/aaaccc
。/aaa/ddd
ファイルがまったくソートされていないと、サブディレクトリが親ディレクトリの前に表示され、問題が困難になります。
最初はsub(...)
行から末尾のスラッシュ(存在する場合)を削除します。行を保存するときに、ファイル名の一部が一致しないように末尾のスラッシュを追加します。
答え4
perl -lne '$l=$_; grep $l =~ m|^\Q$_/|, @A or print, push @A, $_'
- 特定の行に指定されたさまざまなパスをすべて累積しましたが、その行
array @A
にすでに保存されているパスと一致しません。 - grep は
m|^\Q$_/|
配列要素を参照し、一致する項目を探します。
sed -ne '
H # append current line into hold space
g # pattern space = hold space \n current line
y/\n_/_\n/ # change coordinate system
\|_\([^_]*\)_\(.*_\)\{0,1\}\1/|s/\(.*\)_.*/\1/ # match yes, strip current line
y/\n_/_\n/ # revert coordinate system
h # update hold space
$s/.//p # answer
'
出力
/aaa/bbb
/ddd/eee
/fff/ggg
/jjj/kkk/lll/mmm