web-dev-qa-db-ja.com

ファイルのリストをコピー

ファイルにスペースで区切られたファイルのリストがあるlist.txt。新しいフォルダにコピーしたいのですが。

私がやろうとした:

cp `cat list.txt` new_folder

しかし、それはうまくいきませんでした。

これをどうしますか?

更新:

非常に興味深い回答をありがとうございました。私はそんなに求めなかった:)

2回目以上の解決策を試みた後、cpはフォルダーnew_folderdはまだ存在していません!申し訳ありませんが、それは愚かな間違いのようです...以前にフォルダを作成したとき、それは機能します。

しかし、私はあなたのすべての答えと解決策から多くを学びました、あなたがそれらを書くのにかかる時間をありがとう。

36
Klaus

Xargsを使用してみてください。

cat list.txt | xargs -J % cp % new_folder

更新:

GNU/Linuxのバージョンとは異なるバージョンのOS Xでこれを行いました。 GNU findutils に由来するxargsには-Jはありませんが、同様の-Iがあります(Dennis Williamsonがコメントで指摘したように)。 xargsのOS Xバージョンには-I-Jの両方があり、動作はわずかに異なります。どちらもこの元の質問には有効です。

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
34
Doug Harris

catはまったく必要ありません。

xargs -a list.txt cp -t new_folder

または長いオプションを使用する:

xargs --arg-file=list.txt cp --target-directory=new_folder

ここにいくつかのシェルバージョンがあります。ファイル名はスペースで区切られているとOPが指定しているため、一部の変数は引用符で囲まれていないか、forループが具体的に使用されています。これらのテクニックの一部は、ファイル名に空白が含まれている行ごとのファイル名入力では機能しません。

バッシュ:

for file in $(<list.txt); do cp "$file" new_folder; done

または

cp $(<list.txt) new_folder

sh(またはBash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

または

# none here either
while read -r line; do cp $line new_folder; done < list.txt

または

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

または

# meow
cp $(cat list.txt) new_folder

私は前にここで恥ずかしいほど遠回りの回答をしましたが、 Denisの回答 は、最も基本的なことを逃したことを思い出させました。そこで、元の回答を削除しました。しかし、誰もsaidこれは非常に基本的なものではないので、ここに置く価値があると思います。

元の質問は「スペースで区切られたファイル名のリストが記載されたテキストファイルがあります。それらを1つのターゲットディレクトリにコピーするにはどうすればよいですか?」どういうわけか特定の方法でファイルからアイテムを抽出する必要があると思うので、最初はこれはトリッキーまたは複雑に見えるかもしれません。ただし、シェルがコマンドラインを処理する場合、最初に行うことは引数リストをトークンに分離するおよび(ここでは誰もはっきり言っていないビット)スペーストークンを分離するです。 (改行もトークンを区切るため、改行で区切られたリストを使用したDoug Harrisのテストで同じ結果が得られたのはこのためです。)つまり、シェルはスペースで区切られたリストを予期し、すでに処理できます。

したがって、ここで行う必要があるのは、スペース区切りのリスト(既にあるもの)をコマンドの適切な場所に配置することだけです。あなたのコマンドはこれのいくつかのバリエーションです:

_cp file1 file2 file3...file# target
_

唯一のしわは、テキストファイルからファイル1〜#のリストを取得することです。

デニスがコメントで指摘しているように、元の試み(cpcat list.txt _new_folder_)はすでに機能しているはずです。どうして?内部コマンド_cat list.txt_は最初にシェルによって処理され、_file1 file2 file3...file#_に展開されます。これは、シェルがコマンドのその部分で期待および要求するものとまったく同じです。それが機能しない場合は、(1)タイプミスがあったか、(2)ファイル名がどういうわけか奇妙だった(スペースやその他の異常な文字があった)。

Dennisのすべての回答が機能するのは、cpが機能するために必要なファイルのリストを提供し、そのリストをコマンド全体の属する場所に配置するためです。繰り返しますが、コマンド自体は次のような構造になっています。

_cp list-of-files target_directory
_

これがこのバージョンでどのように組み合わされるかを簡単に確認できます。

_cp $(<list.txt) new_folder
_

$() を指定すると、シェルは括弧内のコマンドを実行し、その出力をより大きな行のそのポイントに置き換えます。次に、シェルは行全体を実行します。ちなみに、$()は、バッククォート( `)を使用してすでに実行していたもののより新しいバージョンです。次:_<_はファイルリダイレクト演算子です。これは、シェルに_list.txt_の内容を標準入力にダンプするように指示します。 $()ビットが最初に処理されるため、段階的には次のようになります。

  1. cp $(<list.txt) new_folder# split line into three tokens: cp, $(<list.txt), new_folder
  2. _cp file1 file2 file3...file# new_folder_ # substitute result of $(<list.txt) into the larger command

明らかに、ステップ2はあなたが望んでいた通常のcpコマンドです。

私はこの馬(たぶん非常に死んでいる)をよく叩いていることに気づきましたが、それはやる価値があると思います。シェルがコマンドをどのように処理するかについて正確にを理解することで、コマンドをより適切に記述し、大幅に簡略化することができます。また、問題が隠れている可能性が高い場所も表示されます。この場合、例えば、あなたへの私の最初の質問は、おかしいファイル名または考えられるタイプミスについてだったはずです。アクロバットは必要ありませんでした。

7
Telemachus