Bash:フォルダ構造を維持しながら、名前付きファイルを再帰的にコピーします


103

私は望んでいました:

cp -R src/prog.js images/icon.jpg /tmp/package

宛先ディレクトリに対称構造を生成します:

/tmp
|
+-- package
    |
    +-- src
    |   |
    |   +-- prog.js
    |
    +-- images
        |
        +-- icon.jpg

代わりに、両方のファイルが/ tmp / packageにコピーされます。フラットコピー。(これはOSX上にあります)。

ワイルドカードで指定されたファイル(src / *。jsなど)を含むすべてのファイルを宛先ディレクトリ内の正当な場所にコピーするために使用できる単純なbash関数はありますか?"for each file、run mkdir -p $(dirname "$file"); cp "$file" $(dirname "$file")"と少し似ていますが、おそらく単一のコマンドです。

これは関連するスレッドであり、不可能であることを示唆しています。作成者の解決策は、ワイルドカードであるかどうかに関係なくファイルのリストを提供し、それらすべてを宛先ディレクトリにコピーしてもらいたいので、私にはそれほど役に立ちません。IIRC MS-DOS xcopyはこれを行いますが、cpに相当するものはないようです。

回答:


153

--parentsオプションを使用してみましたか?OS Xでサポートされているかどうかはわかりませんが、Linuxで動作します。

cp --parents src/prog.js images/icon.jpg /tmp/package

それがOS Xで機能しない場合は、

rsync -R src/prog.js images/icon.jpg /tmp/package

aifが提案したように。


4
ありがとう。Macでは「cp --parents」は使用できないことがわかりましたが、他のunixenのフラグを知っておくと便利です。rsync -Rは、この問題に対する最も簡単なポータブルソリューションです。
mahemoff 2009年

1
私はその優雅さ/思い出しやすさのためにこれを受け入れましたが、これは(少なくともOSXでは)ディレクトリ全体をコピーしないのに対し、以下のtarはコピーすることを発見しました。
mahemoff 2012

cp --parentsOSX(BSD cp)では無効なオプションですが、gcp(GNU cp)は正常に動作します。システムにない場合は、を使用してくださいbrew install coreutils。Uにはg-prefixを含む多くのユーティリティがあります。
kyb 2018年

@mahemoff cp -R --parentsおよびrsync -rRファイルとディレクトリの両方を相対的にコピーします。
Vortico

22

一方通行:

tar cf - <files> | (cd /dest; tar xf -)

ああ、私はこれが私の答えよりもずっと好きです。
EMPraptor 2009年

4
この-Cオプションを使用して、chdirを実行することもできますtar cf - _files_ | tar -C /dest xf -
D.Shawley

おかげで、これは簡潔ですが、簡単にするためにrsyncを好みます。
mahemoff 2009年

1
すごい!これをシェルコマンドに変える方法を誰かが知っていますか?N個の入力を受け入れる必要があります。最初のN-1はコピーするファイル、最後はコピー先のフォルダーです。
arod

@arodの$ {#!}が最後のparamで、前の引数を取得するためにこれを使用stackoverflow.com/questions/1215538/...を。コマンドを書く場合は、ここに要旨をリンクしてください。
mahemoff

18

または、古風な場合は、cpioを使用します。

cd /source;
find . -print | cpio -pvdmB /target

明らかに、あなたはあなたの心のコンテンツにファイルリストをフィルタリングすることができます。

「-p」オプションは「パススルー」モード用です(入力の「-i」または出力の「-o」に対して)。'-v'は冗長です(処理されたファイルをリストします)。'-m'は変更時間を保持します。「-B」は「大きなブロック」を使用することを意味します(大きなブロックは512バイトではなく5120バイトです)。最近は効果がない可能性があります。


1
これは、使用することをお勧めします-print0の組み合わせで--null:それは特殊文字とそのように壊れないように、オプションfind . -print0 | cpio -pvdmB --null /target
haridsv

オールドスクールと呼んで、ポータブルと呼んで、なんでも呼んでください。でも、私cpioはこの仕事を信頼しています。-print0-nullオプションを使用する必要があることに同意します。そうしないと、ある時点で、誰かが「特殊文字」(スペース、ほとんどの場合)を含むいくつかのフォルダを提供し、何かが発生します。個人的な経験から言っているわけではありませんが、ファイルの束をバックアップしようとして、ファイル名にスペースが含まれているために、ファイルの半分だけがバックアップされる場合があります。(さて、私は個人的な経験から話しています。)
bballdave025

@ bballdave025:cpioファイル名に改行が含まれている場合にのみ、次の問題が発生します—通常、ファイル名の各改行に対して2つ(またはそれ以上)のファイル名が見つからないというエラーメッセージが表示されます。(メッセージの数が少なくなる場合もありますが、テストケースの作成にはかなりの注意が必要です。)私が使用したときcpio--nullオプションはありませんでした。ダブルダッシュオプションはSVR4オプション表記の一部ではなく、の概念-print0も存在しませんでしたfind。しかし、それはずっと前のことです(たとえば90年代半ば。Linuxが支配的になる前)。
ジョナサンレフラー

詳細をありがとう、@ Jonathan_Leffler。ここで学ぶことが大好きです。今、私はスペースに関する問題を私に与えた再帰コピーの間違いを思い出そうとしています-その間違いをすることができた多くの方法があります
bballdave025

@ bballdave025— 1つの可能性はxargs、混合で使用することです—空白で分割します—空白、タブ、改行。OTOH、どうやって、なぜそうするのかわかりません。cpio出力モードのGNU manulは、1行に約1つのファイル名があります。SVR4ユーザーマニュアル(1990年印刷)は曖昧です:(cpio -oコピーアウトモード)標準入力を読み取ってパス名のリストを取得し、それらのファイルをパス名とステータス情報とともに標準出力にコピーします。したがって、スペースで名前を壊した可能性があります。
ジョナサンレフラー

16

rsyncの-Rオプションは、期待どおりの動作をします。非常に機能豊富なファイルコピー機です。例えば:

$ rsync -Rv src/prog.js images/icon.jpg /tmp/package/
images/
images/icon.jpg
src/
src/prog.js

sent 197 bytes  received 76 bytes  546.00 bytes/sec
total size is 0  speedup is 0.00

結果の例:

$ find /tmp/package
/tmp/package
/tmp/package/images
/tmp/package/images/icon.jpg
/tmp/package/src
/tmp/package/src/prog.js


1

試してみてください...

for f in src/*.js; do cp $f /tmp/package/$f; done

だからあなたが最初にやっていたことは...

for f in `echo "src/prog.js images/icon.jpg"`; do cp $f /tmp/package/$f; done

または

v="src/prog.js images/icon.jpg"; for f in $v; do cp $f /tmp/package/$f; done

必要ないecho$vここに。また、対応するディレクトリが宛先に存在しない場合、このメソッドは失敗します。
Weijun Zhou
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.