Cara menghapus (1) dari nama file menggunakan perintah find

13

Saya baru-baru ini mengkonversi semua file FLAC saya ke tingkat pengambilan sampel yang lebih rendah dari 44,1 kHz dan kedalaman bit 24 bit (karena iPhone / iPod tidak mendukung apa pun di atas itu) menggunakan XLD pada Mac OS 10.7 (Lion).

Meskipun saya mengatakan XLD untuk menimpa semua file sebelumnya, XLD menambahkan (1)di akhir file seperti dari

some_song.m4a

untuk

some_song(1).m4a

Jadi sekarang saya ingin menghapus itu (1)dari semua file FLAC yang saya konversi.

Saya tahu saya mungkin bisa menggunakan beberapa program atau bahkan AppleScript untuk mengganti nama file, tapi saya ingin belajar menggunakan cara baris perintah sekolah yang lama.

Saya tahu bahwa find . -name *\(1\).m4aakan mengambil semua file FLAC yang dikonversi.

Selanjutnya saya tahu saya harus melakukan sesuatu dengan -execdan mvmengubah nama semua file yang ditemukan. Tapi apa yang saya tidak tahu adalah bagaimana menjaga nama file asli dan hanya menghapus (1).

Mungkin saya perlu melakukan beberapa menangkap regex grup untuk menyimpan bagian dari nama file yang saya tidak ingin modifikasi? Atau mungkin itu tidak mungkin untuk melakukan semuanya dalam satu baris dan saya harus membuat skrip shell (yang saya tidak nyaman melakukannya, tapi saya bersedia mencobanya).

Setiap tips atau saran disambut! Terima kasih!

hobbes3
sumber
5
Mengapa downvote? Sepertinya pertanyaan yang valid ...
tidak terkait dengan pertanyaan khusus Anda (pada find) tetapi itu mungkin menyelesaikan masalah Anda yang sebenarnya (mengonversi file audio), Anda mungkin tertarik untuk melihat audiotools.sourceforge.net dan untuk contoh kasus ini (untuk macosx lion) invibe.net/ LaurentPerrinet / SciBlog / 2012-04-22
meduz

Jawaban:

13

Jangan mencoba mengurai findoutput kecuali sebagai pilihan terakhir. Penting untuk disadari bahwa pada sistem file Unix, nama file bukan string (kesalahpahaman umum) melainkan gumpalan biner yang dapat berisi karakter apa pun kecuali /karakter nol. Mem-parsing nama file dengan aman dan benar sudah cukup menyakitkan sehingga 99% dari waktu Anda hanya ingin menghindarinya sama sekali (lihat saja betapa berbulunya sedekspresi dalam jawaban @ yarek dan bahkan itu tidak mencakup semua kasus) . Untungnya, dalam hal ini ada pendekatan yang jauh lebih sederhana:

find . -name '*(1).m4a' -execdir sh -c \
'for arg; do mv "$arg" "${arg%(1).m4a}".m4a; done' _ {} \+
jw013
sumber
pendekatan rapi namun berbulu seperti ekspresi sed :) +1
yrk
1
ada yang hilang di sini ... di mana done?
yrk
@yarek Terima kasih atas tangkapannya. Perbedaan terbesar antara ini dan sedpendekatan pipa adalah ini jauh lebih aman. Ini masih lebih mudah dibaca daripada regex backslash soup, asalkan Anda memahami beberapa konstruksi skrip shell dasar.
jw013
Kamu benar; ini jauh lebih bersih. Dan $argvariabel membuatnya lebih mudah dibaca.
hobbes3
1
@DQdlM Cuplikan yang saya poskan di atas hanya findmenggunakan shsintaks POSIX yang cukup portabel. Untuk detail lebih lanjut, Anda dapat memeriksa bagian pada Parameter Expansion , bagian tentang perintah majemuk yang menjelaskan forloop , dan spesifikasi POSIXfind . Selain sumber daya itu, saya akan dengan senang hati menjawab setiap pertanyaan spesifik yang Anda miliki.
jw013
6

Di Debian dan Ubuntu, saya bisa gunakan rename 's/\(1\)//' *.m4auntuk menyelesaikan masalah Anda.

Dom
sumber
Aneh, saya bisa melakukannya man rename, tetapi sebenarnya saya tidak punya rename: -bash: rename: command not found( which renametidak menunjukkan apa-apa).
hobbes3
@ hobbes3 pada mac di sini man -a renamemenemukan rename (2) - syscall, dan rename (n) - perintah TCL. Ada tidak rename (1) maupun utilitas itu sendiri ada.
tahun
1
IIRC, renameadalah skrip perl yang disertakan dengan contoh-contoh yang disertakan dalam beberapa pemasangan perl, dan beberapa distro memasukkannya dalam path karena itu adalah perintah yang mudah. (@Hobbes mungkin Anda bisa menemukannya di internet)
Kevin
@Kevin pada sistem saya renameadalah biner normal (bukan perl). Namun peringatan lain adalah bahwa tidak semua versi renamemendukung regex. Versi yang saya miliki misalnya hanya memungkinkan Anda melakukan penggantian string langsung, misalnyarename '(1)' '' *.m4a
Patrick
1
renameSkrip Perl hanya diinstal oleh Debian dan turunannya. Sistem Linux lainnya memiliki renameutilitas yang berbeda (ditunjukkan oleh Patrick). OSX tidak memiliki keduanya.
Gilles 'SANGAT berhenti menjadi jahat'
4

Di zsh, menggunakan zmv :

autoload zmv      # you can put this line in your .zshrc
zmv '(*)\(1\)(*)' '$1$2'

Dalam argumen kedua (nama baru), $1dan $2merujuk ke grup yang (PATTERN)di- kurung dalam pola sumber. Cara lain untuk penulisan nama ini adalah

zmv '(*)' '${1/\(1\)/}'
Gilles 'SANGAT berhenti menjadi jahat'
sumber
3

Pendekatan berikut memberi Anda kemampuan untuk melihat dulu / memangkas perintah yang dihasilkan sebelum menjalankannya, dan sangat portabel: itu harus bekerja tidak hanya pada mac, tidak hanya dengan bash, dan tidak hanya dengan GNU sed; bahkan pada sistem tanpa findperintah (1) dimungkinkan untuk menggantikannya dengan du(1) tanpa masalah.

find . -name '*(1).m4a' |
sed 's/\(.*\)(1).m4a$/mv & \1.m4a/' 

Jika senang dengan perintah yang dicetak, jalankan kembali dengan | sh -xmenambahkan.

Jika khawatir tentang ruang dalam nama file, menambah s untuk melarikan diri semua ruang:

find . -name '*(1).m4a' |
sed -e 's/ /\\ /g' -e 's/\(.*\)(1).m4a$/mv & \1.m4a/'

Jika karakter khusus lain diharapkan, ini akan sedikit lebih rumit:

find . -name '*(1).m4a' |
sed -e "s/'/'\\\\''/g" -e 's/\(.*\)(1).m4a$/mv '\''&'\'' '\''\1.m4a'\'/

Fungsi pertama mengkonversi semua 'menjadi bentuk sehingga ini diambil secara harfiah ketika di tengah-tengah '...'string. Fungsi kedua menghasilkan perintah mv yang argumennya disertakan '...'.

yrk
sumber
1
Perintah itu tidak keluar dari nama file (spasi (,, dan semua karakter khusus lainnya) atau menambahkan tanda kutip di sekitar nama file. Saya mencoba mengubah perintah Anda, tetapi saya tidak tahu cara menambahkan tanda kutip di kedua nama file untuk mvperintah. Salah satu output yang dihasilkan dari perintah Anda adalah mv ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us(1).m4a ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us.m4a. Dan jika saya menjalankan perintah itu saya dapatkan -bash: syntax error near unexpected token '('.
hobbes3
ini seharusnya menjadi pekerjaan rumah :) tapi ok, saya akan memperbarui jawabannya
yrk
By the way GNU sed dapat menjalankan perintah itu sendiri dengan menambahkan eperintah setelah substitusi. Sebagai contoh find . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e'akan mengeksekusi perintah tanpa piping ke sh -x.
buru
@ Rush itulah satu-satunya sed yang melakukan itu; dan itu perlu memulai shell, tetapi yang baru untuk setiap perintah (mengingatkan masalah make , bukan?)
yrk
2
Saya tidak berpikir kita harus downvoting. Bagaimanapun, ini adalah solusi yang valid.
hobbes3
1

Berikut ini skrip kecil yang melakukannya:

for var in `find . -type f -name "*(1).m4a"`; do
    new=`echo $var | cut -d'(' -f1`;
    mv $var $new.m4a;
done
anupam
sumber
ini akan tersedak file dengan spasi di namanya; juga membutuhkan penyimpanan sementara yang cukup besar untuk`find ...`
yrk