Saya memiliki dua file dalam folder di Ubuntu 16.04 saya:
a1.dat
b1.DAT
Saya ingin mengubah nama b1.DAT
untuk b1.dat
jadi saya harus mengikuti file sebagai hasil dalam folder:
a1.dat
b1.dat
Saya mencoba (tidak berhasil):
$ rename *.DAT *.dat
Bareword "b1" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
dan
$ find . -iname "*.DAT" -exec rename DAT dat '{}' \;
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
Bareword "DAT" not allowed while "strict subs" in use at (user-supplied code).
Mencari ini tidak menghasilkan solusi yang berarti ...
Jawaban:
Kesalahan itu sepertinya berasal dari Perl
rename
. Anda perlu menggunakan kutipan, tetapi Anda hanya perlu menentukan bagian yang ingin Anda ubah, cari dan ganti gaya. Sintaksnya seperti ini:Hapus
-n
setelah pengujian untuk benar-benar mengganti nama file.Untuk memasukkan file tersembunyi, ubah pengaturan glob sebelum menjalankan perintah:
Jika Anda ingin mengganti nama file secara rekursif, Anda dapat menggunakan
atau jika ada banyak jalur di atau di bawah direktori saat ini yang tidak diakhiri
.DAT
, Anda sebaiknya menentukan jalur tersebut di perintah kedua:Ini akan lebih cepat jika file Anda memiliki berbagai nama berbeda yang tidak berakhir
.DAT
. [1]Untuk mematikan pengaturan ini, Anda dapat menggunakan
shopt -u
, misalnyashopt -u globstar
, tetapi mereka mati secara default dan akan dimatikan saat Anda membuka shell baru.Jika ini menghasilkan daftar argumen yang terlalu panjang, Anda dapat menggunakan, misalnya
find
,:atau lebih baik
Menggunakan
find ... -exec
dengan+
lebih cepat daripada menggunakan\;
karena membangun daftar argumen dari file yang ditemukan. Awalnya saya berpikir bahwa tidak mungkin bagi Anda untuk menggunakannya, karena Anda menyebutkan bahwa Anda memilikiargument list too long
masalah, tetapi sekarang saya tahu bahwa daftar itu juga akan secara cerdik dipecah menjadi beberapa pemanggilan perintah yang diperlukan untuk menghindari masalah itu. [2] .Karena
rename
akan memproses setiap nama file dengan cara yang sama, tidak masalah berapa lama daftar argumen karena dapat dengan aman dibagi di beberapa pemanggilan. Jika perintah yang Anda gunakan-exec
tidak menerima beberapa argumen atau mengharuskan argumennya berada dalam urutan tertentu atau karena alasan lain memecah daftar argumen akan menyebabkan sesuatu yang tidak diinginkan terjadi, Anda dapat menggunakan\;
, yang menyebabkan perintah dipanggil sekali untuk setiap file yang ditemukan (jika daftar argumen terlalu panjang untuk metode lain, ini akan memakan waktu lama!).Terima kasih banyak kepada Eliah Kagan untuk saran yang sangat berguna untuk meningkatkan jawaban ini:
[1] Menentukan nama file saat globbing .
[2]
find ... -exec
dengan+
membagi daftar argumen .sumber
-n
dari mengubah nama setelah pengujian - itu hanya untuk menunjukkan apa yang akan diubahAnda dapat melakukan:
Jatuhkan
-n
agar penggantian nama sebenarnya terjadi.Pola glob
*.DAT
cocok dengan semua file yang berakhir di.DAT
direktori saat inidi
rename
substitusi,DAT$
cocokDAT
di akhir\L$&
membuat seluruh pertandingan lebih kecil;$&
mengacu pada seluruh pertandinganJika Anda hanya ingin melakukannya untuk
b1.DAT
:Contoh:
sumber
Jawaban lain telah membahas salah satu dari dua aspek utama dari pertanyaan ini: yaitu tentang bagaimana cara sukses menjalankan operasi penggantian nama yang Anda butuhkan. Tujuan dari jawaban ini adalah untuk menjelaskan mengapa perintah Anda tidak berfungsi, termasuk arti dari pesan kesalahan "bareword not allowed" yang aneh dalam konteks
rename
perintah.Bagian pertama dari jawaban ini adalah tentang hubungan antara
rename
dan Perl dan bagaimanarename
menggunakan argumen baris perintah pertama yang Anda lewati, yang merupakan argumen kodenya. Bagian kedua adalah tentang bagaimana shell melakukan ekspansi - khususnya globbing - untuk membuat daftar argumen. Bagian ketiga adalah tentang apa yang terjadi dalam kode Perl yang memberikan kesalahan "Bareword not allowed". Akhirnya, bagian keempat adalah ringkasan dari semua langkah yang terjadi antara memasukkan perintah dan mendapatkan kesalahan.1. Saat
rename
memberi Anda pesan kesalahan aneh, tambahkan "Perl" ke pencarian Anda.Di Debian dan Ubuntu,
rename
perintahnya adalah skrip Perl yang melakukan penggantian nama file. Pada rilis yang lebih lama - termasuk 14,04 LTS, yang masih didukung sampai tulisan ini - itu adalah tautan simbolik yang menunjuk ( secara tidak langsung ) keprename
perintah. Pada rilis yang lebih baru, alih-alih menunjuk kefile-rename
perintah yang lebih baru . Mereka dua perintah rename Perl bekerja sebagian besar dengan cara yang sama, dan saya hanya akan merujuk kepada mereka baik sebagairename
untuk sisa jawaban ini.Saat Anda menggunakan
rename
perintah, Anda tidak hanya menjalankan kode Perl yang ditulis orang lain. Anda juga menulis kode Perl Anda sendiri dan menyuruhnyarename
menjalankannya. Ini karena argumen baris perintah pertama yang Anda berikan ke perintah, selain argumen opsi seperti , terdiri dari kode Perl aktualrename
-n
. Therename
perintah menggunakan kode ini untuk beroperasi pada masing-masing nama path yang Anda lulus sebagai argumen baris perintah berikutnya. (Jika Anda tidak memberikan argumen nama path, makarename
bacalah nama path dari input standar , satu argumen per baris.)Kode ini dijalankan dalam loop , yang iterates sekali per pathname. Di bagian atas setiap iterasi dari loop, sebelum kode Anda berjalan,
$_
variabel khusus diberikan pathname yang sedang diproses. Jika kode Anda menyebabkan nilai$_
diubah menjadi sesuatu yang lain, maka file itu diganti namanya untuk memiliki nama baru.Banyak ekspresi dalam Perl beroperasi secara implisit pada
$_
variabel ketika mereka tidak diberi ekspresi lain untuk digunakan sebagai operan . Sebagai contoh, ekspresi substitusi$str =~ s/foo/bar/
perubahan kejadian pertamafoo
dalam string yang diselenggarakan oleh$str
variabel untukbar
, atau daun itu tidak berubah jika tidak mengandungfoo
. Jika Anda hanya menuliss/foo/bar/
tanpa secara eksplisit menggunakan satu=~
operator yang , kemudian beroperasi pada$_
. Ini adalahs/foo/bar/
kependekan dari$_ =~ s/foo/bar/
.Ini umum untuk lulus suatu
s///
ekspresi untukrename
sebagai argumen kode (yaitu, baris perintah argumen pertama), tetapi Anda tidak perlu. Anda dapat memberikan kode Perl apa pun yang Anda inginkan agar dijalankan di dalam loop, untuk memeriksa setiap nilai$_
dan (secara kondisional) memodifikasinya.Ini memiliki banyak konsekuensi keren dan berguna , tetapi sebagian besar dari mereka jauh di luar cakupan pertanyaan dan jawaban ini. Alasan utama saya membawa ini ke sini - pada kenyataannya, alasan utama saya memutuskan untuk mengirim jawaban ini - adalah untuk membuat titik itu, karena argumen pertama
rename
adalah kode Perl, kapan saja Anda mendapatkan pesan kesalahan aneh dan Anda kesulitan menemukan informasi tentang itu dengan mencari, Anda dapat menambahkan "Perl" ke string pencarian (atau bahkan mengganti "ganti nama" dengan "Perl", kadang-kadang) dan Anda akan sering menemukan jawaban.2. Dengan
rename *.DAT *.dat
,rename
perintah tidak pernah melihat*.DAT
!Perintah seperti
rename s/foo/bar/ *.txt
biasanya tidak lulus*.txt
sebagai argumen baris perintah kerename
program, dan Anda tidak menginginkannya , kecuali jika Anda memiliki file yang namanya secara harfiah*.txt
, yang semoga tidak Anda lakukan.rename
tidak menafsirkan pola gumpal seperti*.txt
,*.DAT
,*.dat
,x*
,*y
, atau*
ketika berlalu untuk itu sebagai argumen pathname. Sebagai gantinya, shell Anda melakukan ekspansi pathname pada mereka (yang juga disebut ekspansi nama file, dan juga disebut globbing). Ini terjadi sebelumrename
utilitas dijalankan. Shell memperluas gumpalan ke beberapa nama path yang berpotensi dan melewati semuanya, sebagai argumen baris perintah terpisah, untukrename
. Di Ubuntu, shell interaktif Anda adalah Bash , kecuali Anda telah mengubahnya, itulah sebabnya saya ditautkan ke manual referensi Bash di atas.Ada satu situasi di mana pola gumpalan dapat dilewatkan sebagai argumen baris perintah tunggal yang tidak diperluas untuk
rename
: ketika tidak cocok dengan file apa pun. Kerang yang berbeda menunjukkan perilaku default yang berbeda dalam situasi ini, tetapi perilaku default Bash adalah untuk hanya lulus bola secara harfiah. Namun, Anda jarang menginginkan ini! Jika Anda menginginkannya, maka Anda harus memastikan bahwa polanya tidak diperluas, dengan mengutipnya . Ini berlaku untuk meneruskan argumen ke perintah apa pun, bukan hanya untukrename
.Mengutip tidak hanya untuk globbing (ekspansi nama file), karena ada ekspansi lain yang dilakukan shell Anda pada teks yang tidak dikutip dan, untuk sebagian dari mereka tetapi tidak pada yang lain , juga pada teks yang dilampirkan dalam
"
"
tanda kutip. Secara umum, kapan saja Anda ingin memberikan argumen yang berisi karakter yang dapat diperlakukan secara khusus oleh shell, termasuk spasi, Anda harus mengutipnya, lebih disukai dengan'
'
kutipan .Kode Perl
s/foo/bar/
tidak mengandung apa pun yang diperlakukan secara khusus oleh shell, tetapi itu akan menjadi ide bagus bagi saya untuk mengutipnya juga - dan ditulis's/foo/bar/'
. (Bahkan, satu-satunya alasan aku tidak adalah bahwa itu akan membingungkan untuk beberapa pembaca, karena saya belum berbicara tentang mengutip.) Alasan saya mengatakan ini akan menjadi baik karena itu sangat umum bahwa kode Perl tidak mengandung karakter seperti itu, dan jika saya mengubah kode itu, saya mungkin tidak ingat untuk memeriksa apakah kuotasi diperlukan. Sebaliknya, jika Anda ingin shell untuk memperluas bola, itu tidak harus dikutip.3. Apa yang dimaksud penerjemah Perl dengan "bareword not allowed"
Pesan kesalahan yang Anda tunjukkan dalam pertanyaan Anda mengungkapkan bahwa, ketika Anda berlari
rename *.DAT *.dat
, shell Anda diperluas*.DAT
ke daftar satu atau lebih nama file, dan bahwa yang pertama dari nama file itub1.DAT
. Semua argumen selanjutnya - baik yang lain berkembang dari*.DAT
dan yang diperluas dari -*.dat
datang setelah argumen itu, sehingga mereka akan ditafsirkan sebagai nama path.Karena apa yang benar-benar dijalankan adalah sesuatu seperti
rename b1.DAT ...
, dan karenarename
memperlakukan argumen non-opsi pertamanya sebagai kode Perl, pertanyaannya menjadi: mengapab1.DAT
kesalahan "bareword not allowed" ini muncul ketika Anda menjalankannya sebagai kode Perl?Dalam sebuah shell, kami mengutip string kami untuk melindunginya dari ekspansi shell yang tidak disengaja yang sebaliknya akan mengubahnya menjadi string lain secara otomatis (lihat bagian di atas). Shell adalah bahasa pemrograman tujuan khusus yang bekerja sangat berbeda dari bahasa tujuan umum (dan sintaksis dan semantik yang sangat aneh mencerminkannya). Tetapi Perl adalah bahasa pemrograman tujuan umum dan, seperti kebanyakan bahasa pemrograman tujuan umum, tujuan utama mengutip dalam Perl bukan untuk melindungi string, tetapi untuk menyebutkannya sama sekali. Ini sebenarnya cara sebagian besar bahasa pemrograman mirip dengan bahasa alami. Dalam bahasa Inggris, dan seandainya Anda memiliki anjing, "anjing Anda" adalah frasa dua kata, sedangkan anjing Anda adalah anjing. Demikian pula, dalam Perl,
'$foo'
adalah string, sedangkan$foo
adalah sesuatu yang namanya$foo
.Namun, tidak seperti hampir semua bahasa pemrograman tujuan umum lainnya, Perl juga terkadang akan menafsirkan teks yang tidak dikutip sebagai menyebutkan string - string yang "sama" dengan itu, dalam arti bahwa itu terdiri dari karakter yang sama dalam urutan yang sama. Itu hanya akan mencoba menafsirkan kode seperti itu jika itu adalah kata kunci (tidak
$
atau sigil lainnya, lihat di bawah), dan setelah itu tidak dapat menemukan makna lain untuk memberikannya. Maka itu akan menganggapnya sebagai string, kecuali Anda mengatakannya tidak dengan mengaktifkan pembatasan .Variabel dalam Perl biasanya dimulai dengan karakter tanda baca yang disebut sigil , yang menentukan tipe luas dari variabel. Misalnya,
$
berarti skalar ,@
berarti array , dan%
berarti hash . ( Ada yang lain. ) Jangan khawatir jika Anda merasa membingungkan (atau membosankan), karena saya hanya akan mengatakan bahwa ketika nama yang valid muncul dalam program Perl tetapi tidak didahului oleh sigil, nama itu dikatakan sebagai kata pengantar .Barewords melayani berbagai tujuan, tetapi mereka biasanya menandakan fungsi built-in atau subrutin yang ditentukan pengguna yang telah didefinisikan dalam program (atau dalam modul yang digunakan oleh program). Perl tidak memiliki fungsi bawaan yang disebut
b1
atauDAT
, jadi ketika penerjemah Perl melihat kodeb1.DAT
, ia mencoba memperlakukanb1
danDAT
sebagai nama subrutin. Dengan asumsi tidak ada subrutin seperti itu telah didefinisikan, ini gagal. Kemudian, asalkan pembatasan belum diaktifkan, itu memperlakukan mereka sebagai string. Ini akan berhasil, meskipun apakah Anda benar-benar ingin ini terjadi atau tidak, adalah dugaan siapa pun. Perl.
Operator merangkai string , sehinggab1.DAT
mengevaluasi ke stringb1DAT
. Artinya,b1.DAT
adalah cara yang buruk untuk menulis sesuatu seperti'b1' . 'DAT'
atau"b1" . "DAT"
.Anda dapat menguji ini sendiri dengan menjalankan perintah
perl -E 'say b1.DAT'
, yang meneruskan skrip Perl pendeksay b1.DAT
ke penerjemah Perl, yang menjalankannya, mencetakb1DAT
. (Dalam perintah itu,'
'
kutipan memberitahu shell untuk lulussay b1.DAT
sebagai argumen baris perintah tunggal, jika tidak, ruang akan menyebabkansay
danb1.DAT
akan diuraikan sebagai kata yang terpisah danperl
akan menerima mereka sebagai argumen yang terpisah.perl
Tidak tidak melihat tanda kutip sendiri, karena yang shell menghapusnya .)Tapi sekarang, coba tulis
use strict;
di skrip Perl sebelumnyasay
. Sekarang gagal dengan jenis kesalahan yang sama yang Anda dapatkan darirename
:Ini terjadi karena
use strict;
melarang penerjemah Perl memperlakukan kata kunci bar sebagai string. Untuk melarang fitur khusus ini, itu benar-benar cukup untuk mengaktifkansubs
pembatasan saja. Perintah ini menghasilkan kesalahan yang sama seperti di atas:Tetapi biasanya programmer Perl hanya akan menulis
use strict;
, yang memungkinkansubs
pembatasan dan dua lainnya.use strict;
umumnya direkomendasikan sebagai latihan. Jadirename
perintah melakukan ini untuk kode Anda . Itu sebabnya Anda mendapatkan pesan kesalahan itu.4. Singkatnya, inilah yang terjadi:
b1.DAT
sebagai argumen baris perintah pertama, yangrename
diperlakukan sebagai kode Perl untuk dijalankan dalam satu loop untuk setiap argumen pathname.b1
danDAT
dihubungkan dengan.
operator.b1
danDAT
tidak diawali dengan sigils, jadi mereka diperlakukan sebagai kata pengantar.'b1'
dan'DAT
'dan disatukan. Itu jauh dari yang Anda maksudkan, yang menerangi bagaimana fitur ini seringkali tidak membantu.rename
memungkinkan semua pembatasan (vars
,refs
, dansubs
). Karenanya, Anda malah mendapatkan kesalahan.rename
berhenti karena kesalahan ini. Karena kesalahan semacam ini terjadi lebih awal, tidak ada upaya penggantian nama file yang dilakukan, meskipun Anda belum lulus-n
. Ini adalah hal yang baik, yang sering melindungi pengguna dari perubahan nama file yang tidak disengaja dan kadang-kadang bahkan dari kehilangan data aktual.Terima kasih kepada Zanna , yang membantu saya mengatasi beberapa kekurangan penting dalam draft jawaban ini yang lebih awal . Tanpa dia, jawaban ini akan menjadi jauh lebih masuk akal, dan mungkin tidak diposting sama sekali.
sumber