私は巨大なフォルダツリーを持っており、各フォルダには約3レベル以下のいくつかのサブディレクトリがあります。以下は、レベルが1つしかない例です。
$ tree
.
|-- AB.txt
|-- CD.txt
|-- destination_folder
|-- spreadsheet.txt
`-- subdirectory
`-- EF.txt
2 directories, 4 files
以下の興味のあるファイル名のリストがありますspreadsheet.txt
。
$ cat spreadsheet.txt
AB.txt
CD.txt
EF.txt
spreadsheet.txt
フォルダに表示されるすべてのファイルをコピーしたいですdestination_folder
。助けてくれてありがとう!私はこれが関係すると思いましたが、find
それをcp
理解することはできないようです。
答え1
find
ファイル名に改行文字が含まれていないとし、ファイル名ごとに1回実行します。
#!/bin/sh
mkdir -p destination_folder || exit 1
while IFS= read -r name; do
find . -path ./destination_folder -prune -o \
-type f -name "$name" -exec cp {} destination_folder \;
done <spreadsheet.txt
まず、現在のディレクトリ内にターゲットディレクトリを作成します(または失敗すると終了します)。次に、入力ファイルを 1 行ずつ読み込み、呼び出して、find
その名前の一般ファイルを探します。検索でターゲットディレクトリが見つかるたびに、次を使用して明示的find
にこれを回避します。-prune
正しい名前のファイルが見つかると、そのファイルがターゲットディレクトリにコピーされます。複数のファイルの名前が同じ場合はコピーをdestination_folder
上書きします。
現在のディレクトリが大きい場合、またはファイル名のリストが長い場合(ただし数千行ではない)、作業が遅くなります。だから私たちは一つ私たちに電話してくださいfind
。以下のコードはbash
配列を使用しているため、たとえば実行されているとします。
#!/bin/bash
mkdir -p destination_folder || exit 1
names=()
while IFS= read -r name; do
names+=( -o -name "$name" )
done <spreadsheet.txt
find . -path ./destination_folder -prune -o \
\( "${names[@]:1}" \) -type f -exec cp -t destination_folder {} +
ここでは、見つかったファイルごとに1回ではなく、できるだけ少ない数の呼び出しを実行するためにcp -t
(GNUcp
拡張)を使用することにしました。cp
上記のコードはnames
最終的にfind
。あなたの質問の例によれば、上記のコードの最後で実行される実際のコマンドは次のようになります。
find . -path ./destination_folder -prune -o '(' -name AB.txt -o -name CD.txt -o -name EF.txt ')' -type f -exec cp -t destination_folder '{}' +
ターゲットディレクトリ内のファイル名の競合の問題を回避するには、GNUを使用する場合(Linuxシステムなど)またはオプションをcp
使用してください。cp
-b
--backup
Linux以外のシステムでは、通常、cp
パッケージマネージャを介してGNU coreutilsをインストールした後にGNUを使用できます。gcp
最後のスクリプト/bin/sh
(無制限の配列):
#!/bin/sh
mkdir -p destination_folder || exit 1
set --
while IFS= read -r name; do
set -- -o -name "$name" "$@"
done <spreadsheet.txt
shift
find . -path ./destination_folder -prune -o \
\( "$@" \) -type f -exec cp -t destination_folder {} +
答え2
シンプルな for ループ:
for filename in $(cat spreadsheet.txt)
do
find . -name "$filename" -exec cp {} /destination/folder \;
done