直前のパスよりも深いテキストファイルのパスをフィルタリングします。

直前のパスよりも深いテキストファイルのパスをフィルタリングします。

ソートされたパスのリストを含むテキストファイルがある場合は、その親パス(直接かどうかにかかわらず)もリストにあるため、重複するすべてのパスを削除するにはどうすればよいですか?

たとえば、

/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

関連情報