Ganti nama beberapa file menggunakan skrip Bash

27

Saya ingin mengganti nama banyak file di direktori yang sama menggunakan skrip Bash. Nama file adalah sebagai berikut:

file2602201409853.p
file0901201437404.p  
file0901201438761.p  
file1003201410069.p  
file2602201410180.p

Saya ingin mengganti nama ke format berikut:

file2503201409853.p
file2503201437404.p  
file2503201438761.p  
file2503201410069.p  
file2503201410180.p

Saya membaca tentang perintah rename, dan mencoba melakukannya dengan cara ini, tetapi tidak melakukan apa-apa, saya pikir saya memiliki pertanyaan tentang sintaks. Lalu saya membaca bahwa Anda dapat membuat loop menggunakan perintah mv sebagai berikut:

for file in cmpsms*2014*.p; do
    mv "$file" "${file/cmpsms*2014*.p/cmpsms25032014*.p}"
done

Tapi saya tidak bisa mengganti nama file. Apa yang saya lakukan salah?

franvergara66
sumber
2
Anda tidak dapat memiliki ekspresi pola di sisi kanan ekspresi penggantian ekspansi parameter. Apa yang Anda harapkan di tempat itu *?
kojiro
@ Kiwy Pertanyaan itu adalah tentang menghapus sebagian dari nama file. Ergo, duplikat sangat diragukan.
CVn
2
Lain kali, tolong jelaskan perubahan nama file yang ingin Anda buat (saya harus melihat ini untuk sementara waktu sebelum melihat perbedaan dan kesamaan). Contohnya bagus, tetapi deskripsi serta contohnya bahkan lebih baik.
CVn

Jawaban:

42

Anda benar untuk mempertimbangkan mengganti nama terlebih dahulu. Sintaksnya sedikit aneh jika Anda tidak terbiasa dengan regex tetapi ini adalah rute tercepat / terpendek begitu Anda tahu apa yang Anda lakukan:

rename 's/\d{4}/2503/' file*

Itu hanya cocok dengan 4 angka pertama dan menukarnya dengan yang Anda tentukan.

Dan test harness ( -vnartinya verbose tetapi tidak melakukan apa - apa) menggunakan nama file Anda:

$ rename 's/\d{4}/2503/' file* -vn
file0901201437404.p renamed as file2503201437404.p
file0901201438761.p renamed as file2503201438761.p
file1003201410069.p renamed as file2503201410069.p
file2602201409853.p renamed as file2503201409853.p
file2602201410180.p renamed as file2503201410180.p
Oli
sumber
8
Perhatikan bahwa ini adalah perubahan nama Perl pada Debian dan turunannya (Ubuntu, Mint, ...). Pada distribusi Linux lainnya, renameadalah alat penggantian nama file yang sama sekali berbeda (yang dikirimkan oleh Debian rename.ul).
Gilles 'SANGAT berhenti menjadi jahat'
Jika Anda kekurangan alat seperti itu, lihat jawaban @Michael Campbell. Saya pikir setiap distributif mengganti default renameseperti yang dilakukan debian.
Astery
25

Ini harus melakukan trik:

for f in file*; do mv $f ${f/${f:4:8}/25032014}; done

Ini menggantikan string antara karakter ke-4 dan ke-12 dengan "25032014".

kekacauan
sumber
ini for f in file*; do mv $f ${f/${f:4:4}/2503}; donejuga berfungsi.
Avinash Raj
Itu bagus. Jika Anda hanya ingin melakukan penggantian kata secara teratur, ini berfungsi seperti sed. misfor f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Eric
1
@ Eric - Saya memposting jawaban Anda sebagai alternatif karena saya pikir ini lebih jelas dan elegan. Jika Anda juga ingin mempostingnya sebagai jawaban - Saya akan menghapus milik saya. Terima kasih!
Yehosef
Mengapa kutip ganda hilang ?
Wildcard
Ini memberi saya kesalahan: "mv: target 'FILE_NAME' bukan direktori"
Aubrey
10

ini benar-benar jawaban @ Eric dari atas - tapi ini jawaban yang elegan jadi saya mengeposnya sebagai jawaban yang tepat untuk menarik lebih banyak perhatian padanya.

for f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Yehosef
sumber
1
ptrn='file[0-9][0-9][0-9][0-9]2014[0-9][0-9][0-9][0-9][0-9].p'
path=/dir
( set -- "${path}/"${ptrn} ; for f ; do {
    echo "mv ${path}/${f} \
        ${path}/file25032014${f#2014}" 
} ; done )

Ini harus melakukan trik. Catatan - Saya tidak terbiasa menyerahkan perintah massal mv - seperti yang tertulis itu hanya gema. Anda harus menyelesaikannya sebelum berhasil.

mikeserv
sumber
1

Cara asli yang sederhana untuk melakukannya tanpa perulangan, dengan direktori traversal :

find -type f | xargs -I {} mv {} {}.txt

Ini akan mengganti nama setiap file di tempat.

Dan di bawah ini contoh kerja dengan paralelisasi :

find -name "file*.p" | parallel 'f="{}" ; mv -- {} ${f:0:4}2503${f:8}'
dtrckd
sumber
Itu adalah pendekatan pertama yang mudah untuk membayangkan solusi yang lebih baik. Jika Anda ingin perintah yang berfungsi, lakukan:
dtrckd
find -type f -name "file*.p" | parallel 'ext="{}" ; mv -- {} ${ext:0:4}2503${ext:8}'
dtrckd
0

Jika Anda sering melakukan hal semacam ini, cari "rename.pl". Ini adalah skrip perl, tetapi memungkinkan Anda untuk hanya memberinya kode perl (seperti /// ekspresi), dan itu akan melakukan pengubahan nama massal berdasarkan pada ekspresi atau kode tersebut.

Ada versi dasar di sini: http://stackoverflow.org/wiki/Rename.pl tetapi ada versi lain yang beredar di internet. Sudah ada selama berabad-abad.

Michael Campbell
sumber