Cara menyalin file ke beberapa direktori menggunakan perintah gnu cp

210

Apakah mungkin menyalin satu file ke beberapa direktori menggunakan perintah cp?

Saya mencoba yang berikut, yang tidak berhasil:

cp file1 /foo/ /bar/
cp file1 {/foo/,/bar}

Saya tahu ini mungkin menggunakan for for, atau temukan. Tetapi apakah mungkin menggunakan perintah gnu cp?

Tom Feiner
sumber

Jawaban:

106

Tidak, cpdapat menyalin beberapa sumber tetapi hanya akan menyalin ke satu tujuan. Anda perlu mengatur untuk memohon cpbeberapa kali - sekali per tujuan - untuk apa yang ingin Anda lakukan; menggunakan, seperti yang Anda katakan, loop atau alat lain.

bayangan bulan
sumber
Terima kasih atas jawabannya! Sekarang saya berpikir tentang itu sedikit lebih, tanpa bendera tambahan (yang tidak ada) cp tidak akan tahu apa sumbernya dan apa DEST dir.
Tom Feiner
10
Ini bukan jawaban yang benar. Silakan lihat jawaban Robert Gamble.
PlagueHammer
23
@Nocturne: bagian mana dari apa yang saya katakan salah? Robert memberi contoh menggunakan alat lain untuk memohon cp beberapa kali seperti yang saya sarankan. Ada banyak kemungkinan solusi yang melibatkan penggunaan alat atau konstruksi lain untuk melakukan itu, tetapi OP memang mengindikasikan ia sudah sadar bahwa itu mungkin.
moonshadow
2
Sedih, akan bagus untuk cp (dan scp) untuk mendukung fitur itu. Namun kita dapat menggunakan tee untuk melakukan split. superuser.com/questions/32630/…
Simon
4
@moonshadow: Tentu saja jawaban Anda benar. Saya pikir PlagueHammer ingin mengatakan bahwa dalam konteks ini jawaban yang lain lebih berguna. Mungkin Anda bisa memasukkan sesuatu seperti itu dalam jawaban Anda juga?
Damai
585

Anda tidak dapat melakukan ini cpsendirian, tetapi Anda dapat menggabungkan cpdengan xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Akan menyalin file1untuk dir1, dir2, dan dir3. xargsakan menelepon cp3 kali untuk melakukan ini, lihat halaman manual xargsuntuk detailnya.

Robert Gamble
sumber
3
Informasi lebih lanjut tentang xargs: cyberciti.biz/faq/…
Chris Bier
24
@Simon bagaimana? "Kamu tidak bisa melakukan ini cpsendirian" Hanya karena jawabannya berusaha membantu dengan menyarankan cara lain tidak berarti pertanyaannya tidak dijawab.
Nicole
3
@NickC Penanya menentukan: "Saya tahu itu mungkin menggunakan for for, atau menemukan. Tetapi apakah mungkin menggunakan perintah gnu cp?" Jawaban yang bagus adalah jawaban yang diterima.
Simon
25
Menetapkan bahwa jawaban diterima berdasarkan apakah mereka secara teknis menjawab pertanyaan itu akan menjadi sangat tidak masuk akal dan tidak terlalu berguna.
Backgammon
4
Sangat membantu! Untuk pemula lain seperti saya: Anda tidak bisa menggunakan regex dengan cp, tetapi Anda bisa di bagian pertama dari perintah ini (misalnya echo dir[1-3] | xargs -n 1 cp filename).
Jason
77

Wildcard juga berfungsi dengan kode Roberts

echo ./fs*/* | xargs -n 1 cp test 
Paul
sumber
dan seluruh komentar ... Misalnya, untuk memindahkan file yang dimiliki oleh root (sebenarnya symlink) yang ada di desktop saya ke semua pengguna desktop, pertama saya harus sudo su (tidak berfungsi sebaliknya) kemudian digunakan: echo / home / * / Desktop / | xargs -n 1 cp -av / home / myusername / Desktop / file.
David G
19

Sejauh yang saya bisa melihatnya, Anda dapat menggunakan yang berikut:

ls | xargs -n 1 cp -i file.dat

The -ipilihan cpberarti perintah yang Anda akan ditanya apakah akan menimpa file dalam direktori saat ini dengan file.dat. Meskipun ini bukan solusi yang sepenuhnya otomatis, ini berhasil untuk saya.

Evgeny
sumber
1
Meskipun bagus untuk menambahkan -ipenjaga, bukankah itu akan meminta Anda untuk menulis setiap file? daripada menyalin ke direktori?
Hedgehog
1
@ Landak Yah, saya pikir bahwa perintah ini berguna ketika ada file di direktori dan orang ingin menyalinnya ke subdirektori direktori. Dalam hal ini file hanya dapat ditimpa satu kali. Terima kasih atas pertanyaan anda!
Evgeny
2
Bagi saya, itu mencetak serangkaian cp: overwritepertanyaan, tetapi saya tidak harus menjawabnya, dan itu tidak menimpa file.
Evgeni Sergeev
Juga mencetak serangkaian pertanyaan + disalin ke file dengan nama dir dengan karakter ':' pada akhirnya, tidak ada solusi yang berfungsi sama sekali, solusi Paul bekerja dengan sempurna
jgpATs2w
19

Saya akan menggunakan catdan teeberdasarkan jawaban yang saya lihat di /superuser/32630/parallel-file-copy-from-single-source-to-multiple-targets alih-alih cp.

Sebagai contoh:

cat inputfile | tee outfile1 outfile2 > /dev/null
deterb
sumber
1
Tes sepintas yang baru saja saya jalankan menunjukkan ini untuk menjadi pemain terbaik jika tujuan Anda adalah drive fisik yang berbeda (menyimpan dua salinan fisik dari basis file seperti video sumber untuk film digital).
Penasaran
1
Jika Anda menggunakan bash 3.0 atau lebih tinggi, Anda dapat menggunakan rentang sebagai berikut:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Samuel
tee < inputfile outfile1 outfile2 > /dev/nulljuga merupakan pola yang bermanfaat seperti yang ditunjukkan oleh jawaban Taywee. Perhatikan penggunaan io-redirection dengan '<' sehingga pemipaan dari kucing tidak diperlukan.
Alex Telon
10

Semua jawaban ini tampaknya lebih rumit daripada yang sudah jelas:

for i in /foo /bar; do cp "$file1" "$i"; done
Waxrat
sumber
yang elegan dan berfungsi, untuk melakukannya untuk semua direktori dalam direktori saat ini, dapat digunakanfor d in */ ; do cp $file "$i" done
FantomX1
9

ls -db di*/subdir | xargs -n 1 cp File

-bdalam kasus ada spasi dalam nama direktori jika tidak maka akan rusak sebagai item yang berbeda oleh xargs, punya masalah dengan versi gema

thAAAnos
sumber
6

Tidak menggunakan cp per se, tapi ...

Ini muncul bagi saya dalam konteks menyalin banyak rekaman GoPro dari kartu SD (lambat) ke tiga (lambat) drive USB. Saya ingin membaca data hanya sekali, karena butuh selamanya. Dan saya ingin itu bersifat rekursif.

$ tar cf - src | tee >( cd dest1 ; tar xf - ) >( cd dest2 ; tar xf - ) | ( cd dest3 ; tar xf - )

(Dan Anda dapat menambahkan lebih banyak bagian> () tersebut jika Anda menginginkan lebih banyak keluaran.)

Saya belum membandingkannya, tapi pasti jauh lebih cepat daripada cp-in-a-loop (atau banyak permintaan paralel cp).

oggust
sumber
5

Untuk menggunakan menyalin dengan xargske direktori menggunakan wildcard pada Mac OS, satu-satunya solusi yang bekerja untuk saya dengan spasi dalam nama direktori adalah:

find ./fs*/* -type d -print0 | xargs -0 -n 1 cp test 

Di mana testfile untuk menyalin
Dan./fs*/* direktori untuk menyalin

Masalahnya adalah bahwa xargs melihat spasi sebagai argumen baru, solusi untuk mengubah karakter pembatas menggunakan -datau -Esayangnya tidak berfungsi dengan baik pada Mac OS.

MegaCookie
sumber
4

Jika Anda ingin melakukannya tanpa perintah bercabang:

tee <inputfile file2 file3 file4 ... >/dev/null

Taywee
sumber
2

Pada dasarnya setara dengan jawaban xargs, tetapi jika Anda ingin eksekusi paralel:

parallel -q cp file1 ::: /foo/ /bar/

Jadi, misalnya, untuk menyalin file1 ke semua subdirektori folder saat ini (termasuk rekursi):

parallel -q cp file1 ::: `find -mindepth 1 -type d`

NB: Ini mungkin hanya menyampaikan kenaikan kecepatan yang terlihat untuk kasus penggunaan yang sangat spesifik, misalnya jika setiap direktori target adalah disk yang berbeda.

Secara fungsional juga mirip dengan argumen '-P' untuk xargs.

alainv
sumber
0

Tidak Anda tidak bisa.

Saya telah menemukan beberapa kali bahwa saya dapat menggunakan fungsi ini sehingga saya membuat alat sendiri untuk melakukan ini untuk saya.

http://github.com/ddavison/branch

cukup mudah -
branch myfile dir1 dir2 dir3

ddavison
sumber
Sering ada skenario di mana saya akan menulis skrip saya sendiri, tetapi saya cenderung menggunakan begitu banyak mesin saat ini sehingga menjaga semuanya dalam sinkronisasi sepertinya menjadi masalah besar. Kalau saja ada cara untuk memasang direktori web cloud /emisalnya, hanya sekali pada setiap mesin, maka saya bisa menulis powertools saya sendiri dan menyimpannya selamanya.
Evgeni Sergeev
0
ls -d */ | xargs -iA cp file.txt A
Sj Lee
sumber
1
Bagaimana dengan sedikit penjelasan?
mnt
Ini sebenarnya bekerja, tetapi sebuah penjelasan akan sangat bagus
Ælex
0

Misalkan Anda ingin menyalin fileName.txtke semua sub-direktori dalam direktori kerja ini.

  1. Dapatkan semua nama sub-direktori melalui lsdan simpan ke beberapa file sementara mengatakan,allFolders.txt

    ls > allFolders.txt
  2. Cetak daftar dan berikan kepada perintah xargs.

    cat allFolders.txt | xargs -n 1 cp fileName.txt
Devendra Lattu
sumber
0

Cara lain adalah dengan menggunakan cat dan tee sebagai berikut:

cat <source file> | tee <destination file 1> | tee <destination file 2> [...] > <last destination file>

Saya pikir ini akan sangat tidak efisien, karena pekerjaan akan dibagi di antara beberapa proses (satu per tujuan) dan hard drive akan menulis beberapa file sekaligus di berbagai bagian platter. Namun jika Anda ingin menulis file ke beberapa drive yang berbeda, metode ini mungkin akan sangat efisien (karena semua salinan dapat terjadi secara bersamaan).

jww
sumber
0

Menggunakan skrip bash

DESTINATIONPATH[0]="xxx/yyy"
DESTINATIONPATH[1]="aaa/bbb"
                ..
DESTINATIONPATH[5]="MainLine/USER"
NumberOfDestinations=6

for (( i=0; i<NumberOfDestinations; i++))
    do
        cp  SourcePath/fileName.ext ${DESTINATIONPATH[$i]}

    done
exit
Patrick Manley
sumber
Saya memberikan downvote ini. Pertanyaan khusus meminta solusi non-loop.
Alex Telon
-1

jika Anda ingin menyalin beberapa folder ke beberapa folder, seseorang dapat melakukan sesuatu seperti ini:

echo dir1 dir2 dir3 | xargs -n 1 cp -r / path / toyourdir / {subdir1, subdir2, subdir3}

Ishak
sumber
-1

Jika semua direktori target Anda cocok dengan ekspresi jalur - seperti mereka semua adalah subdirektori dari path/to- maka gunakan findkombinasi dengan cpseperti ini:

find ./path/to/* -type d -exec cp [file name] {} \;

Itu dia.

Mig82
sumber
Saya memberikan downvote ini. Pertanyaannya secara khusus menanyakan solusi yang tidak ditemukan.
Alex Telon
Terima kasih karena telah mengerjakan @AlexTelon secara menyeluruh. Saya kira saya melewatkan sedikit itu. Saya harap Anda konsisten juga dan memberikan suara untuk setiap jawaban lainnya menggunakan findutas.
Mig82
-2

Jika Anda harus spesifik pada folder mana untuk menyalin file, Anda dapat menggabungkan find dengan satu atau lebih greps. Misalnya untuk mengganti kejadian favicon.ico di subfolder apa pun yang dapat Anda gunakan:

find . | grep favicon\.ico | xargs -n 1 cp -f /root/favicon.ico
Kristofer
sumber
-3

Ini akan menyalin ke sub-direktori langsung, jika Anda ingin masuk lebih dalam, sesuaikan -maxdepthparameternya.

find . -mindepth 1 -maxdepth 1 -type d| xargs -n 1 cp -i index.html

Jika Anda tidak ingin menyalin ke semua direktori, semoga Anda dapat memfilter direktori yang tidak Anda sukai. Contoh menyalin ke semua folder dimulai dengan a

find . -mindepth 1 -maxdepth 1 -type d| grep \/a |xargs -n 1 cp -i index.html

Jika menyalin ke direktori direktori yang sewenang-wenang / terpisah, Anda memerlukan saran Robert Gamble.

landak
sumber
-3

Saya suka menyalin file ke beberapa direktori seperti itu: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ Dan menyalin direktori ke direktori lain: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

Saya tahu ini seperti mengeluarkan beberapa perintah, tetapi bekerja dengan baik ketika saya ingin mengetikkan 1 baris dan berjalan pergi untuk sementara waktu.

Stace Fauske
sumber
7
Anda menjawab pertanyaan 6 tahun dengan 15 jawaban lainnya. Jawaban Anda harus sangat baru. Pendapat saya - tidak.
Craig S. Anderson
-4

Misalnya jika Anda berada di direktori induk folder tujuan Anda, Anda dapat melakukannya:

untuk saya dalam $ (ls); lakukan cp sourcefile $ i; selesai

Behrooz
sumber
Pertanyaannya mengatakan itu mungkin dengan loop for, jadi ini benar-benar tidak menambahkan apa pun.
LJNielsenDk
Diturunkan. Jangan pernah mencoba mem-parsing output darils , dan selalu mengutip variabel. for i in ./*; do cp sourcefile "$i"; done
sleblanc