入力ファイルを使用してファイルをコピーしてファイルの方向を読み込みます。

入力ファイルを使用してファイルをコピーしてファイルの方向を読み込みます。

grep1TBのファイルを検索するために使用しています。ファイル名をgrepし、名前をテキストファイルに入れたいので、cpdirと一致するすべてのファイルが欲しいです/home/user/matches。すべてのファイルを2回grepingせずに両方の操作を実行したいと思います。

私の考えは、grepを使用してファイル名の出力をテキストファイルに入れることです。

grep -ril "xxx" . >> /home/user/matches/output-filename.txt

これでoutput-filename.txtcpへの入力として機能し、cpが1行ずつ実行されるようにします。どうすればいいですか?え?それとも、すべてのファイルを2回検索しないようにする他のアイデアはありますか?

答え1

ファイルパスはゼロ以外のバイトシーケンスです。テキスト行はもちろん、テキストである必要はありません。特にファイルパス

  • 改行文字を含めることができます。
  • 有効な文字を形成しないバイトシーケンスを含めることができます。
  • LINE_MAXより長い場合があります。

GNU実装grep(オプションを追加した実装-r)はテキスト以外の形式でパスを印刷でき、-Z後処理に安全です。たとえば、GNUはxargsオプションを使用してこの形式を処理できます-0

xargs -r0 -a <(
  grep -rilZ xxx . |
   tee file.list
)  cp -it /home/user/matches --

(これもGNUをオプションcpと仮定します-t

GNUを使用して人が読めるテキスト形式でリストを印刷するには、次の手順を実行しますprintf

xargs -r0a file.list printf '%q\n'

1文字が表現としてレンダリングされるため、デコードできないバイトを保証する必要があります$'\234'$'\n'サポートLINE_MAXする行数に制限はありません)。

答え2

find一対の接続コマンドを使用できますexecgrepすべてのファイル(および一致するすべてのファイル)に対して呼び出されるため、最も効率的な解決策ではないかもしれませんが、cpファイル名の文字に関係なく機能します。

mkdir -p ~/matches
find -type f -exec grep -il 'xxx' {} \; -exec cp -p {} ~/matches/ \; > ~/matches/output-filename.txt

答え3

このようにしてくださいteexargsコマンド(NULL byte \0ファイル名区切り文字の末尾として使用)とGNU grep:

スペース、改行などを使用してファイル名を処理します。

mkdir -p ~/matches
grep -Zril "xxx" . |
    tee ~/matches/output-filename.txt |
    xargs -0 -I {} cp {} ~/matches/

関連情報