すべての入力ファイルは既に並べ替えsort -mられているため、実際の並べ替え手順を省略して、ファイルをマージするためにのみ使用できます。
一部のUnixシステム(私の知る限り Linux のみ)では、これで十分な場合があります
sort -m *.words | uniq -d >dupes.txt
複製された行をファイルに書き込むためdupes.txt。
これらの行がどのファイルからのものかを見つけるには、次のようにします
grep -Fx -f dupes.txt *.words
これはgrep、dupes.txt(-f dupes.txt)の行を固定文字列パターン(-F)として扱うように指示します。grepまた、行全体が最初から最後まで完全に一致する必要があります(-x)。ファイル名と行を端末に出力します。
Linux以外のUnices(またはさらに多くのファイル)
一部のUnixシステムでは、30000のファイル名が単一のユーティリティに渡すには長すぎる文字列に拡張されます(つまり、OpenBSDシステムではでsort -m *.words失敗しArgument list too longます)。Linuxでさえ、ファイル数がはるかに多い場合、これについて不満を言うでしょう。
だまし絵を見つける
一般的な場合(これはまた、意志と仕事していることをこの意味多く:ちょうど30000ファイル以上)、1ソート「チャンク」にあり
rm -f tmpfile
find . -type f -name '*.words' -print0 |
xargs -0 sh -c '
if [ -f tmpfile ]; then
sort -o tmpfile -m tmpfile "$@"
else
sort -o tmpfile -m "$@"
fi' sh
または、tmpfileなしで作成xargs:
rm -f tmpfile
find . -type f -name '*.words' -exec sh -c '
if [ -f tmpfile ]; then
sort -o tmpfile -m tmpfile "$@"
else
sort -o tmpfile -m "$@"
fi' sh {} +
これにより、現在のディレクトリ(またはその下)で名前がと一致するすべてのファイルが検索されます*.words。一度に適切なサイズのこれらの名前のチャンク(サイズはxargs/ によって決定さfindれtmpfileます)の場合、それらはソートされたファイルにマージされます。tmpfileすでに存在する場合(最初のチャンクを除くすべて)、このファイルは現在のチャンク内の他のファイルともマージされます。ファイル名の長さとコマンドラインの最大許容長に応じて、内部スクリプトを個別に10回以上実行する必要があります(find/ xargsにより自動的に実行されます)。
「内部」shスクリプト、
if [ -f tmpfile ]; then
sort -o tmpfile -m tmpfile "$@"
else
sort -o tmpfile -m "$@"
fi
用途sort -o tmpfile出力にするtmpfile(これは上書きされませんtmpfile、これはまたに入力された場合でもsortと)-mマージを行うため。両方のブランチで、または"$@"からスクリプトに渡される個別に引用されたファイル名のリストに展開されます。findxargs
次に、実行uniq -dしtmpfileて複製されたすべての行を取得します。
uniq -d tmpfile >dupes.txt
"DRY"原則( "Do n't Repeat Yourself")が好きな場合は、内部スクリプトを次のように書くことができます。
if [ -f tmpfile ]; then
t=tmpfile
else
t=/dev/null
fi
sort -o tmpfile -m "$t" "$@"
または
t=tmpfile
[ ! -f "$t" ] && t=/dev/null
sort -o tmpfile -m "$t" "$@"
彼らはどこから来ましたか?
上記と同じ理由grep -Fx -f dupes.txt *.wordsで、これらの重複がどこから来たかを見つけるのに使用できないので、代わりにfindもう一度使用します。
find . -type f -name '*.words' \
-exec grep -Fx -f dupes.txt {} +
実行する「複雑な」処理はないため、grepから直接呼び出すことができ-execます。この-execオプションはユーティリティコマンドを受け取り、見つかった名前をに配置し{}ます。では+最後に、findの代わりに多くの引数として配置されます{}ユーティリティを呼び出すたびに、現在のシェルの支持体として。
であるためには、完全に正しい、1のいずれかを使用することもできます
find . -type f -name '*.words' \
-exec grep -H -Fx -f dupes.txt {} +
または
find . -type f -name '*.words' \
-exec grep -Fx -f dupes.txt /dev/null {} +
ファイル名が常にからの出力に含まれるようにしてくださいgrep。
最初のバリエーションはgrep -H、常に一致するファイル名を出力するために使用します。最後のバリエーションでは、コマンドラインで複数のファイルを指定したgrep場合に、一致するファイルの名前が含まれるという事実を使用しています。
grepから送信されたファイル名の最後のチャンクにfindは、実際には単一のファイル名しか含まれていない可能性があるため、これは問題になりgrepます。
ボーナス素材:
find+ xargs+ shコマンドを分析する:
find . -type f -name '*.words' -print0 |
xargs -0 sh -c '
if [ -f tmpfile ]; then
sort -o tmpfile -m tmpfile "$@"
else
sort -o tmpfile -m "$@"
fi' sh
find . -type f -name '*.words'現在のディレクトリ(またはその下)からパス名のリストを生成します。各パス名は通常のファイル(-type f)のパス名で、末尾にファイル名コンポーネントがと一致し*.wordsます。現在のディレクトリのみを検索する場合は、の-maxdepth 1後.、の前に追加でき-type fます。
-print0見つかったすべてのパス名が区切り文字として\0(nul)文字を使用して出力されるようにします。これはUnixパスでは無効な文字であり、改行文字(または他の奇妙なもの)が含まれている場合でもパス名を処理することができます。
find出力をにパイプしますxargs。
xargs -0\0パス名の-区切りリストを読み取り、指定されたユーティリティをこれらのチャンクで繰り返し実行します。これにより、入力がなくなるまで、シェルが長すぎる引数リストについて文句を言わないように十分な引数でユーティリティが実行されます。からfind。
呼び出されるユーティリティがxargsありsh、その使用して文字列として、コマンドラインで指定されたスクリプトを使用して-cフラグ。
起動するとsh -c '...some script...'、次の引数で、引数は、スクリプトを利用できるようになり$@、最初の引数を除いに配置されます、$0(これはあなたが例えばのスポットことを「コマンド名」であるtopあなたが速い十分にある場合)。これがsh、実際のスクリプトの終了後、最初の引数として文字列を挿入する理由です。文字列shは仮引数であり、任意の単一の単語にすることができます(一部の_ユーザーはまたはを好むようですsh-find)。
fi' shますか?