ファイルから同じテキスト項目を検索するシェルスクリプト

ファイルから同じテキスト項目を検索するシェルスクリプト

スクリプトを作成する必要があります。

  1. 複数のテキストファイルを含むディレクトリをインポートします。複数個であり、最大1000個まで可能です。
  2. すべてのファイルには、指定された行(常に同じ行)に識別子が含まれています。
  3. 一意でない識別子を持つファイル、つまりディレクトリ内の他のファイルに重複したファイルを識別します。
  4. 重複リストのエクスポートまたは保存

これは、一意である必要があるがユーザーエラーのため一意ではない可能性があるシステム生成ファイルの日常的な管理「クリーンアップ」に必要です。

ベストアンサー1

上記のコメントに基づいて、私のテストデータが実際のデータと非常によく似ていることを確認して、次のことを確認できました。

grep -n '^ID.[^:-]*.[0-9][0-9]*$' |
sed -n 'h;s|\(.*\):6:\(ID.*\)|\2|p;g;s||\2:\1|p'
sort -u | 
sed 's|ID..*:||'

私のgrepフォルダには、一致するファイルが複数見つかり、一致する行番号を印刷するように要求IDするため、次に始まる行と残りの行が含まれています。-ngrep

[filename]:[matching line number]:[IDmatch]

sed前のバッファに行のコピーを保存するためにそれを渡し、文字列を確認し、h見つかっ:6:IDた場合はその行を削除しますID。次にp結果を印刷します。

次に、gバッファを返し(プロセスの最後の編集内容を上書きし)、grep一致するファイル名の位置に一致行を置き換えます。したがって、grep6行に一致する印刷されたすべての行をsed次のように置き換えます。

[IDmatch]
[IDmatch]:[filename]

このデータが渡されると、sortコレクション全体を整理しID、一意の結果のみを提供するように要求するため、-u重複IDmatch行を除くすべての行が削除され、次のIDmatch:filename行は保持されます。次sedのステートメントはそれをクリーンアップして次のようにレンダリングします。

ID00000000
ID00000000:file00
ID00000000:file10
...
ID00000000:file80
ID00000001
ID00000001:file01
ID00000002
ID00000002:file02
...

このように:

ID00000000
file00
file10
...
file80
ID00000001
file01
ID00000002
file02
...

しかし、その解決策〜するファイル名に\newline文字が含まれている場合は中断されますが、次はそうではありません。 2回接地する必要がないように、次をシェル関数に入れる方法を見つけました。すぐにここに貼り付けます。

for f in * ; do
    sed '5!d;s|^|: "${'$((i=i+1))'}" |;q' "$f"
done |
sort -t' ' -k3 |
uniq -D -f2 |
sh -cx "$(cat)" -- * 2>&1

これは可能でなければなりません。ステートメントのID行をに5置き換えます。sed私の考えでは - 私が間違っている場合はお知らせください - これはすべてのケースを処理します。

ディレクトリ内の各ファイルに対して数字を1ずつ増やし、文字列で始まる行を印刷します。

: "${[num]}" ...

...ここで[num]1だけ増加した実際の整数であり、...行の一意のIDです。

次に、その行を最初にパイプしてsort文字<space>を区切り文字として処理し、3番目のフィールドのデータのみを並べ替えます。|pipeline横にある続行は、入力を比較し、重複行のみを印刷しながら、入力の最初の2つのフィールドを分離してスキップしますuniq。次の部分は少し奇妙です。<space>-D

したがって、再度繰り返して、どのファイルが何であるかを調べるのではなく、前述の作業を実行し[num]ました。sh最終シェルプロセスが結果に合格すると、|pipelineこの数だけが受け取ります。ただし、すでに数値を増やしたときに繰り返されたのと同じグローバル変数に設定されている位置パラメータがあるため、その数値を評価するときに既に位置配列内のファイルに関連付けます。それがすべてです。

事実 – ほとんどそうしません。各位置パラメータの前には:NULLコマンドがあります。シェルプロセスが実行する唯一のことは、渡された変数を評価することです。 1行のコードも実行しません。しかし、デバッグモードに設定し、すべてのファイル名を印刷するようにリダイレクト-xしました。stderrstdout

これは、奇妙なファイル名が結果を台無しにすることを心配するよりもsort | uniqはるかに簡単なためです。そしてそれは素晴らしい作品です。

次の方法で生成されたデータセットを使用してこれをテストしました。

tr -dc '[:graph:]' </dev/urandom |
dd ibs=100 cbs=10 conv=unblock count=91 |
split -b110 --filter='
{   c=${FILE##%%*0} ; c=${c#file}
    sed "5cID000000${c:-00}"
} >$FILE' -ed - file ; rm *90*

rm上記の文字列を参照してください。ちょっと眠いので、なぜ102バイトだけが生成され、残りの110バイトは生成されないのかを確認したくなかったので、file8990に四捨五入してrm編集しました。上記のコマンドを実行すると、rmファイル名が現在のディレクトリのglobと一致し、file00その中のすべてのファイルが上書きされます。file89ただし、委任されたテストディレクトリ内で使用することは完全に安全です。

...何よりも...誰にも効果があります。

file[0-8][1-9]これにより、それぞれ1-4,6-10 10バイトのランダムなデータ行と呼ばれる90個のファイルが作成され、各ファイルの行5に一意のIDがあります。また、file[0-8]0常に行5を生成しますID00000000

このデータセットで実行される最上位の小さな関数の出力は次のとおりです。

+ : file10 ID00000000
+ : file00 ID00000000
+ : file20 ID00000000
+ : file30 ID00000000
+ : file40 ID00000000
+ : file50 ID00000000
+ : file60 ID00000000
+ : file70 ID00000000
+ : file80 ID00000000

+何らかの理由で出力のシンボルが気に入らない場合は、$PS4最後のシェルプロセスを変更してください。最後の行の先頭に次を追加すると、この問題を処理できます。

PS4= sh ...

ただし、必要に応じてシェルスクリプトの実行可能ビットまで任意の文字列に設定することもでき、必要に応じてファイル名を区別します。デフォルトでは、ヒントを自動区切り記号として自由に使用できます。最後のシェルプロセスにはまだ配列のファイル名が含まれています。必要に応じてデータを操作するコマンドを追加できます。

おすすめ記事