Bagaimana cara menyalin beberapa file dengan wildcard?

42

Saya memiliki folder dengan sejumlah file di dalamnya ABC. * (Ada sekitar 100 file seperti itu). Saya ingin menduplikasi semuanya ke file baru dengan nama yang dimulai dengan DEF. *

Jadi aku ingin

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

disalin ke

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

Apa cara paling sederhana untuk melakukan ini dengan perintah batch (dalam BASH atau serupa)? Saya sedang memikirkan sesuatu yang melibatkan sed atau awk atau xargs, tetapi saya mengalami kesulitan mencari tahu sintaksnya. Saya bisa menulis skrip Python, tapi saya pikir mungkin ada solusi baris perintah yang tidak terlalu rumit.

Gurita
sumber
mcManajer file yang terhormat memiliki dukungan paling luas untuk jenis penggantian nama massal ini.
oakad
@ Oakad tarjuga bukan ayam musim semi. Lihat jawaban saya sebagai contoh.
mikeserv

Jawaban:

41

Bagaimana dengan yang seperti ini di bash:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

Anda dapat mengujinya dengan meletakkan gema di depan perintah cp:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done
Magnus
sumber
sempurna. bahkan lebih sederhana dari yang saya bayangkan.
Octopus
Ini akan cukup baik dalam banyak kasus tetapi memeriksa dengan gema sangat penting di sini. Jangan pernah melakukan ini dalam naskah . Untuk info lebih lanjut baca bash pitfalls
pawel7318
@ pawel7318, tautan yang Anda berikan, meskipun saran yang sangat bagus, tampaknya tidak berlaku untuk perintah yang diberikan di atas. Satu-satunya kasus tepi yang saya lihat dengan perintah ini adalah: (1) Tidak memeriksa apakah file target sudah ada atau apakah file target sudah ada sebagai direktori (yang akan menyalin file ke direktori, mempertahankan nama saat ini), dan (2) jika ada begitu banyak file sehingga ekspansi glob tidak dapat masuk ke dalam satu baris perintah.
Wildcard
1
Saya mendapatkan ini: cp /usr/local/lib/libboost* /usr/local/lib/libboost*dengan gema cek.
Tomáš Zato
8

Untuk melakukan ini secara efisien dengan sejumlah besar file, lebih baik untuk menghindari memulai cpproses yang berbeda untuk masing-masing file . Salah satu caranya adalah dengan menyalin kemudian mengganti nama mereka menggunakan prename( renamedisinkronkan dengan ini secara default pada distro berbasis Debian). Menggunakan ini dan Linux mktemp:

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

Memperbarui

Sebenarnya paxmungkin cara yang lebih baik untuk pergi ke sini:

pax -rws '/^ABC/DEF/' ABC.* .

Sayangnya, meskipun paxPOSIX dan Linux Standard Base, beberapa distro saat ini memasukkannya secara default.

Graeme
sumber
sentuhan yang bagus menggunakan: sebagai pemisah untuk menghindari melarikan diri.
Clayton Stanley
5

tar akan melakukan ini untuk Anda sangat cepat.

UJI

Pertama saya membuat 2 direktori dan 10 file:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

Lalu saya menyalinnya:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

MENGUBAH

Jadi GNU tarakan menerima sed --transform=EXPRESSIONpenggantian nama file. Ini bahkan dapat mengganti nama hanya beberapa file. Contohnya:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

Jadi itu satu keuntungan.

ALIRAN

Juga pertimbangkan bahwa ini hanya dua tarproses - dan itu tidak akan berubah terlepas dari jumlah file Anda.

tar | tar

tardioptimalkan seperti yang Anda inginkan. Ini tidak akan pernah memiliki jumlah argumen masalah atau proses anak kabur. Ini hanya A> B selesai.

ARGUMEN

Saya menggunakan 7 argumen berbeda yang digabungkan antara dua tarproses saya di sini. Yang paling penting tercantum di sini terlebih dahulu:

-stdout / stdin - ini menginformasikan tarbahwa itu akan streaming baik input atau output ke atau dari stdin/stdoutmana ia akan menafsirkan dengan benar tergantung pada apakah itu membangun atau mengekstraksi arsip.

-cbuat - ini memberitahu taruntuk membangun arsip. Argumen berikutnya tarmengharapkan ...

-ffile - kami menentukan bahwa tarakan bekerja dengan fileobjek daripada perangkat tape atau apa pun. Dan file yang akan dikerjakannya, seperti disebutkan di atas, adalah stdin/stdout- dengan kata lain, file kita |pipe.

./*semua $ PWD / file - tidak terlalu banyak untuk menjelaskan di sini kecuali bahwa argumen arsip datang pertama, sehingga -kemudian ./*.

... dan di sisi lain |pipe...

-Cubah direktori - ini menginformasikan tarbahwa perlu mengubah ke direktori yang saya tentukan sebelum melakukan tindakan lain, sehingga efektif cd ../test2sebelum ekstraksi.

--transform='s/ed/EXPR/'- Seperti yang telah disebutkan, ini mengganti nama. Tetapi dokumen menunjukkan bahwa itu dapat mengambil sedekspresi apa pun atau //flag.

-xekstrak - setelah tarperubahan ke direktori target kami dan menerima instruksi penggantian nama kami, kami menginstruksikannya untuk mulai mengekstraksi semua file ke direktori saat ini dari -f - |pipefile arsip. Tidak ada misteri.

mikeserv
sumber
1
Inilah paxsolusi untuk pertanyaan ini. Saya akan menambahkannya ke jawaban saya, tetapi saya pikir ini lebih cocok di sini -pax -rws '/^ABC/DEF/' ABC.* .
Graeme
@Graeme - woah - itu jauh lebih baik! Sobat, ini juga mengalahkan nama mutiara! Anda harus meletakkan ini dalam jawaban Anda - paxditentukan POSIX - maka dari itu pax.
mikeserv
paxmungkin POSIX, tetapi sayangnya jarang diinstal secara default.
Graeme
4

Jika Anda tidak keberatan menggunakan alat yang kurang standar, saya sarankan menggunakan mmv (perpindahan massal) yang ditulis untuk tugas yang sangat baik ini. Menggunakan mcp(salinan massal), yang merupakan bagian dari suite, Anda bisa melakukannya

mcp "ABC.*" "DEF.#1"

Tidak mudah menemukan paket unduhan. Paket Debian saat ini (yang juga digunakan Arch dalam AUR) untuk dikompilasi di rumah dapat ditemukan di sini .

Jonny
sumber
menginstal di ubuntu 15.10 di luar kotak,apt-get install mmv
Thufir
2

Di zsh, masukkan baris berikut di Anda .zshrc:

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

Kemudian, pada baris perintah, Anda dapat menjalankan

zcp 'ABC(.*)' 'DEF$1'

atau sederhana

zcp -W ABC.* DEF.*

Di shell lain, selama Anda menginstal zsh:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'
Gilles 'SANGAT berhenti menjadi jahat'
sumber
1

Anda bisa melakukan ini:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done
Sara Fauzia
sumber
Mungkin ada sesuatu yang tidak saya lihat, tetapi bagaimana saya menetapkan beberapa tujuan? Saya menggunakan for loop untuk mendapatkan masing-masing. Saya telah menguji kode sebelumnya, dan itu berfungsi seperti yang diharapkan, jadi saya akan sangat menghargai penjelasan Anda.
Sara Fauzia
Itu salah saya, saya salah membaca jawaban Anda. :-)
Chris Down
Bagaimana saya harus membaca "${i#*.}"bit?
dumbledad