すべての入力ファイルは既に並べ替え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
マージを行うため。両方のブランチで、または"$@"
からスクリプトに渡される個別に引用されたファイル名のリストに展開されます。find
xargs
次に、実行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
ますか?