Menyalin satu file ke beberapa direktori menggunakan cp

12

Pertanyaan ini adalah sekuel dari pertanyaan saya sebelumnya, Membuat banyak direktori menggunakanmkdir .

Saya menggunakan bashshell. Saya telah membuat lima puluh direktori, masing-masing dimulai dengan awalan "s", menggunakan perintah:

mkdir $(printf "s%02i " $(seq 1 50))

yang bantalan ke digit kedua dengan nol. Artinya, direktori yang saya mendapatkan adalah dalam bentuk s01, s02, ..., s49, s50.

Sekarang saya ingin menggunakan cpuntuk menyalin satu file (misalnya, test.txt) ke masing-masing dari lima puluh direktori. Apakah mungkin melakukan ini dengan cara yang analog dengan yang di atas? Misalnya, apakah pekerjaan berikut akan berhasil? Saya relatif baru di Unix / Linux, jadi saya tidak benar-benar ingin mencoba ini sampai seseorang tolong beri saya indikasi bahwa itu aman.

cp test.txt $ (printf "s% 02i.txt" $ (seq 1 50))

Melihat manhalaman untuk cp, sepertinya tidak cpmendukung banyak tujuan seperti ini, namun:

NAME
       cp - copy files and directories

SYNOPSIS
       cp [OPTION]... [-T] SOURCE DEST
       cp [OPTION]... SOURCE... DIRECTORY
       cp [OPTION]... -t DIRECTORY SOURCE...

DESCRIPTION
       Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

       Mandatory  arguments  to  long  options are mandatory for short options
       too.
Andrew
sumber

Jawaban:

7

Jika Anda ingin menggunakan output dari perintah Anda untuk menyalin file ke setiap direktori menggunakan cp, Anda selalu bisa mengirimnya ke xargs:

printf "s%02i " $(seq 1 50) | xargs -n 1 cp test.txt

Seharusnya tidak ada kekhawatiran tentang keamanan parsing output karena Anda tahu format dan kontennya sebelumnya - risiko bertemu karakter meta dan ruang dalam nama file tidak benar-benar masalah di sini.

Atau, dengan asumsi direktori sudah ada, Anda dapat mencoba sesuatu seperti:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -print0 | xargs -0 -I {} cp test.txt {}

atau tanpa pipa:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -exec cp test.txt {} \;

Dua perintah terakhir akan menemukan file apa pun di direktori saat ini dan cp test.txtke mereka. The -maxdepth 1pilihan akan menghindari sub direktori menerima file juga. Diperingatkan bahwa 's[0-9][0-9]'adalah pencocokan terhadap sdiikuti oleh dua digit, yang berarti jika untuk beberapa alasan Anda harus s99dalam cwd, juga akan menerima salinan test.txt.

tojrobinson
sumber
8

Anda juga dapat membiarkan shell melakukan iterasi dengan satu forlingkaran. Ini adalah cara paling dasar yang tidak bergantung pada alat eksternal seperti parallelatau xargs, dan saya merasa paling mudah untuk memahami:

for name in $(printf "s%02i " $(seq 1 50)); do
    mkdir $name
    cp test.txt $name
done

Ada sejuta cara lain untuk menulis ini, misalnya:

for name in $(seq -w 1 50); do
    mkdir s$name
    cp test.txt s$name
done

Jika Anda ingin memverifikasi apa yang akan dieksekusi sebelum melakukannya, Anda dapat melakukan sesuatu seperti menambahkan perintah terlebih dahulu echo, yang akan mencetak baris daripada menjalankannya:

for name in $(seq -w 1 50); do
    echo mkdir s$name
    echo cp test.txt s$name
done

output:

mkdir s01
cp test.txt s01
mkdir s02
cp test.txt s02
mkdir s03
cp test.txt s03
# etc.
Jim Paris
sumber
2

Anda juga bisa menggunakan paralel GNU . Dengan asumsi Anda berada di direktori yang berisi text.txt dan 50 dir Anda berada di /my/50dirs/path(seperti /my/50dirs/path/s01, /my/50dirs/path/s02dll) Anda akan menjalankan:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}
don_crissti
sumber
2
Lebih baik membuatnya parallel -j1, jika tidak akan ada satu pekerjaan per inti, dan pada mesin multicore pekerjaan akan bersaing untuk IO.
Gilles 'SO- stop being evil'