Yeniden adlandırma, birden çok dosya adının parçalarını küçük harfle yazmaya çalışırken "bareword'a izin verilmiyor" ifadesini döndürür


12

Ubuntu 16.04'ümdeki bir klasörde iki dosya var:

a1.dat
b1.DAT

Ben adlandırmak istediğiniz b1.DATiçin b1.datben klasörde sonucunda dosyaları aşağıdaki olurdu böylece:

a1.dat
b1.dat

Denedim (başarısız):

$ 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).

ve

$ 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).

Bunu aramak anlamlı bir çözüm getirmedi ...


Ayrıca
mmv

Yanıtlar:


14

Bu hata Perl'den geliyor gibi görünüyor rename. Tırnak işareti kullanmanız gerekir, ancak yalnızca değiştirmek istediğiniz bölümü belirtmeniz, arama ve değiştirme stilini belirtmeniz gerekir. Sözdizimi şöyle:

rename -n 's/\.DAT/\.dat/' *

-nDosyaları gerçekten yeniden adlandırmak için test ettikten sonra kaldırın .

Gizli dosyaları dahil etmek için, komutu çalıştırmadan önce glob ayarını değiştirin:

shopt -s dotglob

Dosyaları özyinelemeli olarak yeniden adlandırmak istiyorsanız,

shopt -s globstar
rename -n 's/\.DAT/\.dat/' **

veya geçerli dizinde bitmeyen veya bitmeyen çok sayıda yol varsa .DAT, ikinci komutta bu yolları daha iyi belirttiniz:

rename -n 's/\.DAT/\.dat/' **/*.DAT

Dosyalarınızda bitmeyen çeşitli farklı adlar varsa, bu daha hızlı olacaktır .DAT. [1]

Bu ayarları kapatmak için shopt -u, örneğin kullanabilirsiniz , shopt -u globstarancak varsayılan olarak kapalıdır ve yeni bir kabuk açtığınızda kapalı olacaktır.

Bu aşırı uzun bir argüman listesiyle sonuçlanırsa, örneğin şunları kullanabilirsiniz find:

find -type f -name "*.DAT" -exec rename -n -- 's/\.DAT/\.dat/' {} \;

ya da daha iyisi

find -type f -name "*.DAT" -exec rename -n -- 's/\.DAT/\.dat/' {} +

Bulunan dosyalardan bir bağımsız değişken listesi oluşturduğu için find ... -execile kullanmak , kullanmaktan +daha hızlıdır \;. Başlangıçta bunu kullanmanın mümkün olmayacağını düşündüm, çünkü bir argument list too longsorun yaşadığınızı söylemiştiniz , ancak şimdi listenin bu sorunu önlemek için gerektiğinde komutun çoklu çağrılarına da zekice bölüneceğini biliyorum. [2] .

Yana renameaynı şekilde her dosya adı işleyecek, güvenle birden çağırmaları arasında bölünebilir olarak argüman listesi ne kadar önemli değildir. Birlikte kullandığınız komut -execbirden fazla bağımsız değişkeni kabul etmiyorsa veya bağımsız değişkenlerinin belirli bir sırada olmasını veya bağımsız değişken listesinin başka bir nedenden dolayı bölünmesini istemiyorsanız, istenmeyen bir şeyin \;olmasına neden olur, bu da komutun bir kez çağrılmasına neden olur bulunan her dosya için (argüman listesi diğer yöntemler için çok uzunsa, bu uzun zaman alacaktır!).


Bu cevabı iyileştirmek için çok yararlı öneriler için Eliah Kagan'a çok teşekkürler :

[1] Globbing sırasında dosya adlarını belirtme .
[2] find ... -execile +argüman listesini böler .


Teşekkürler. Yinelemeli olarak nasıl yapılır (tüm alt klasörlerdeki tüm dosyalar için)?
Samo

@Samo görmek benim düzenleme :)
Zanna

Çalışmıyor: $ rename 's / \. DAT / \. Dat /' ** bash: / usr / bin / rename: Bağımsız değişken listesi çok uzun
Samo

1
@Samo, -ntest ettikten sonra yeniden adlandırmadan kaldırmanız gerekiyor - sadece neyin değişeceğini göstermek için
Zanna

1
Centos ve Arch'da yeniden adlandırma bu davranışı göstermez. WSL'de Debian'ı kullanmaktan buraya geldim. Bu sözdizimi işe yaradı.
xtian

6

Yapabilirsin:

rename -n 's/DAT$/\L$&/' *.DAT

-nGerçek yeniden adlandırma işleminin gerçekleşmesi için bırakın .

  • glob pattern geçerli dizinde *.DATbiten tüm dosyalarla eşleşir.DAT

  • içerisinde renamebireyin ikame, DAT$stoktaki DATsonunda

  • \L$&tüm maçı küçük harflerle gösterir; $&tüm maçı ifade eder

Sadece aşağıdakileri yapmak istiyorsanız b1.DAT:

rename -n 's/DAT$/\L$&/' b1.DAT

Misal:

% rename -n 's/DAT$/\L$&/' *.DAT
rename(b1.DAT, b1.dat)

4

Diğer cevaplar , bu sorunun iki önemli özelliğinden birini ele aldı: ihtiyaç duyduğunuz yeniden adlandırma işlemini nasıl başarılı bir şekilde gerçekleştireceğiniz. Bu cevabın amacı, komutun içeriğindeki garip "bareword izin verilmiyor" hata mesajının anlamı da dahil olmak üzere komutlarınızın neden çalışmadığını açıklamaktır rename.

Bu cevabın ilk bölümü renamePerl ile Per arasındaki ilişki ve onu ilettiğiniz renameilk komut satırı argümanını (kod argümanı) nasıl kullandığına ilişkindir. İkinci bölüm, bir bağımsız değişken listesi oluşturmak için kabuğun genişlemeleri - özellikle de globbing - nasıl gerçekleştirdiğiyle ilgilidir. Üçüncü bölüm Perl kodunda "Bareword'a izin verilmiyor" hataları verenlerin ne olduğuyla ilgilidir. Son olarak, dördüncü bölüm, komut girme ve hata alma arasındaki tüm adımların bir özetidir.

1. renameSize garip hata mesajları verdiğinde, aramanıza "Perl" ekleyin.

Debian ve Ubuntu'da renamekomut, dosya yeniden adlandırma gerçekleştiren bir Perl betiğidir. Daha eski sürümlerde - 14.04 LTS dahil , bu yazıdan hala desteklenmektedir - komuta işaret eden ( dolaylı olarak ) sembolik bir bağlantıydı . Daha yeni sürümlerde, bunun yerine yeni komut işaret edilir. Bu iki Perl yeniden adlandırma komutu çoğunlukla aynı şekilde çalışır ve her ikisine de bu cevabın geri kalanında olduğu gibi atıfta bulunacağım.prenamefile-renamerename

renameKomutu kullandığınızda, yalnızca başka birinin yazdığı Perl kodunu çalıştırmazsınız. Ayrıca kendi Perl kodunuzu yazıyorsunuz ve renameçalıştırmayı söylüyorsunuz . Bunun nedeni ilk komut satırı argümanı size iletmek renamedışında komutu, seçenek argümanlar gibi -n, fiili Perl koddan oluşur . renameKomut her ameliyat için bu kodu kullanan yol adlarının Eğer sonraki komut satırı argümanları olarak geçirebilirsiniz. (Herhangi bir yol adı bağımsız değişkeni renameiletmezseniz , her satırda bir tane olmak üzere standart girişten yol adlarını okur .)

Kod içinde çalıştırılan bir döngü , dolaşır yol adı bir kere. Döngünün her yinelemesinin üstünde, kodunuz çalışmadan önce özel $_değişkene o anda işlenmekte olan yol adı atanır. Kodunuz değerinin $_başka bir şeyle değiştirilmesine neden oluyorsa, bu dosya yeni ada sahip olacak şekilde yeniden adlandırılır.

Perl'deki birçok ifade , işlenen$_ olarak kullanmak için başka bir ifade verilmediğinde değişken üzerinde dolaylı olarak çalışır . Örneğin ikame sentezleme ilk geçtiği değişikliği tarafından tutulan dize değişken için , ya da yapraklar değişmeden bu içermiyorsa . Sadece yazarsanız açıkça kullanmadan operatörü , o zaman çalışır . Bu kısa demek .$str =~ s/foo/bar/foo$str barfoos/foo/bar/=~$_s/foo/bar/$_ =~ s/foo/bar/

Bu geçmesine yaygındır bir s///ifadeyi için renamekod argüman (yani ilk komut satırı argümanı) olarak, ancak gerekmez. Döngünün içinde çalışmasını, her değerini incelemek $_ve (koşullu olarak) değiştirmek için herhangi bir Perl kodunu verebilirsiniz .

Bunun çok güzel ve yararlı sonuçları var , ancak bunların büyük çoğunluğu bu soru ve cevabın kapsamı dışında. Bunu buraya getirmemin ana nedeni - aslında, bu cevabı göndermeye karar vermemizin ana nedeni - çünkü ilk argümanın renameaslında Perl kodu olduğu, her zaman garip bir hata mesajı aldığınız ve arama yaparak bu konuda bilgi bulmakta sorun yaşıyorsanız, arama dizesine "Perl" ekleyebilir (hatta bazen "rename" yerine "Perl" yazabilirsiniz) ve genellikle bir yanıt bulacaksınız.

2. İle rename *.DAT *.dat, renamekomut hiç görmedim *.DAT!

Gibi bir komut rename s/foo/bar/ *.txttipik geçmez *.txtbir komut satırı argümanı olarak renameprogram ve bunu istemiyoruz , adı tam anlamıyla bir dosya yoksa *.txtumarım, değil mi.

renameyorumlayamaz glob desenleri gibi *.txt, *.DAT, *.dat, x*, *y, veya *yol adı argüman olarak kendisine geçirilen zaman. Bunun yerine, kabuğunuz üzerinde yol adı genişletmesi gerçekleştirir (buna dosya adı genişletmesi de denir ve aynı zamanda globbing de denir). Bu renameyardımcı program çalıştırmadan önce olur . Kabuk için, potansiyel olarak çok sayıda yol adlarının içine globs genişler ve ayrı komut satırı bağımsız değişken olarak, hepsini geçer rename. Ubuntu'da, değiştirmedikçe interaktif kabuğunuz Bash'tır , bu yüzden yukarıdaki Bash referans kılavuzuna bağlandım .

Bir glob kalıbının genişletilmemiş tek bir komut satırı argümanı olarak iletilebileceği bir durum vardır: herhangi bir dosyayla renameeşleşmediğinde. Farklı mermiler bu durumda farklı varsayılan davranışlar sergiler, ancak Bash'ın varsayılan davranışı, küreyi kelimenin tam anlamıyla geçmektir. Ancak, nadiren bunu istiyorsun! Eğer istediyseniz, alıntı yaparak kalıbın genişletilmediğinden emin olmalısınız . Bu, yalnızca komutlara değil, herhangi bir komuta argüman iletmek için de geçerlidir .rename

Alıntılama yalnızca globbing (dosya adı genişletme) için değildir, çünkü kabuğunuzun alıntılanmamış metin üzerinde gerçekleştirdiği diğer genişletmeler ve bazıları için değil, diğerleri için de " "tırnak içine alınmış metinler vardır. Genel olarak, boşluklar da dahil olmak üzere kabuk tarafından özel olarak işlenebilecek karakterler içeren bir argümanı geçmek istediğinizde, bunu tercihen ' 'tırnak işaretleri ile vermelisiniz .

Perl kodu s/foo/bar/, kabuk tarafından özel olarak işlenmiş hiçbir şey içermez, ancak bunu da alıntılamak ve yazmak benim için iyi bir fikir olurdu 's/foo/bar/'. (Aslında, benim yaptığım tek nedeni değil henüz alıntı anlattı olmasaydı gibi, bazı okuyuculara kafa karıştırıcı olacağını idi.) Nedeni ben Perl kodu çok yaygın olduğu için bu olurdu iyi olduğunu söylemek yok içerirler Bu karakterleri değiştirirsem ve bu kodu değiştirirsem, alıntı yapmanın gerekli olup olmadığını kontrol etmeyi hatırlamayabilirim. Buna karşılık, kabuğun bir küreyi genişletmesini istiyorsanız, alıntı yapılmamalıdır .

3. Perl tercümanı "bareword'a izin verilmez" ile ne demek

Sorunuzda gösterdiğiniz hata mesajları, koştuğunuzda rename *.DAT *.datkabuğunuzun *.DATbir veya daha fazla dosya adı listesine genişlediğini ve bu dosya adlarının ilki olduğunu ortaya çıkarır b1.DAT. Takip eden tüm argümanlar - her ikisi de bu argümandan sonra --came'den *.DATgenişletilmiş ve *.dat--came'den genişletilmiştir , böylece yol adları olarak yorumlanırlardı.

Çünkü aslında neyin koştu gibi bir şey oldu rename b1.DAT ..., çünkü renamePerl kodu olarak davranır ilk seçenek olmayan argüman, soru olur: neden yok b1.DATsen Perl kodu olarak bunu çalıştırdığınızda bu "bareword izin verilmez" hataları üretmek?

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).

Bir kabukta, onları otomatik olarak diğer dizelere otomatik olarak dönüştürecek istenmeyen kabuk genişlemelerinden korumak için dizelerimizi alıntılarız (yukarıdaki bölüme bakın). Kabuklar, genel amaçlı dillerden çok farklı çalışan özel amaçlı programlama dilleridir (ve çok tuhaf sözdizimleri ve anlambilimleri bunu yansıtır). Ancak Perl, genel amaçlı bir programlama dilidir ve çoğu genel amaçlı programlama dili gibi Perl'de alıntı yapmanın temel amacı, dizeleri korumak değil , onlardan bahsetmektir. Bu aslında çoğu programlama dilinin doğal dile benzemesinin bir yoludur. İngilizceniz varsa ve bir köpeğiniz olduğunu varsayarsak, "köpeğiniz" iki kelimelik bir kelime iken köpeğiniz bir köpektir. Benzer şekilde, Perl'de, '$foo'bir dize, $fooadı olan bir şeydir $foo.

Ancak, hemen her diğer genel amaçlı programlama dili aksine Perl olacak da bazen tırnaksız metni yorumlamak söz o aynı karakterlerden oluşmaktadır anlamında, o kadar "aynı" olan bir dize - bir dize aynı sipariş. Kodu sadece bir bareword ise (hayır $veya başka bir sigil varsa , aşağıya bakın) ve bunu vermek için başka bir anlam bulamadığında yorumlamaya çalışacaktır . Daha sonra kısıtlamaları etkinleştirerek söylemediğiniz sürece onu bir dize olarak alacaktır .

Perl'deki değişkenler tipik olarak değişkenin geniş türünü belirten sigil adı verilen noktalama işaretiyle başlar . Örneğin, $anlamına gelir skaler , @araçlar dizisi ve %araçlar karma . ( Başkaları da var. ) Eğer kafa karıştırıcı (veya sıkıcı) fark ederseniz Do not endişe, Tek söylemek o kadar getiriyorum çünkü bir geçerli bir ad , bir Perl programda görünür ama değil bir desen öncesinde, bu ad bir bareword olduğu söylenir .

Barewords çeşitli amaçlara hizmet eder, ancak genellikle programda (veya program tarafından kullanılan bir modülde) tanımlanmış yerleşik bir işlevi veya kullanıcı tanımlı bir alt yordamı belirtir. Perl hiçbir adlandırılan yerleşik işlevleri olan b1veya DATPerl yorumlayıcı kodu gördüğünde bu nedenle, b1.DATbu tedavi etmeye çalışır b1ve DATaltrutinlerin adları gibi. Bu tür altprogramların tanımlanmadığı varsayılarak bu başarısız olur. Daha sonra, kısıtlamalar etkinleştirilmemişse, bunları dize olarak kabul eder. Aslında olsun veya olmasın rağmen bu çalışacaktır amaçlanan bunun olmasını kimse bilemez. Perl .operatörü dizeleri birleştirir , bu nedenle b1.DATdizeyi değerlendirirb1DAT. Yani, veya b1.DATgibi bir şey yazmak için kötü bir yoldur .'b1' . 'DAT'"b1" . "DAT"

perl -E 'say b1.DAT'Kısa Perl betiğini say b1.DATçalıştıran Perl yorumlayıcısına ileten komutu yazdırarak bunu kendiniz test edebilirsiniz b1DAT. (Bu komutta, ' 'tırnak geçmesine kabuk söylemek say b1.DATtek komut satırı argümanı olarak, aksi takdirde, uzay neden olur sayve b1.DATgereken ayrı kelimeler olarak ayrıştırılır ve perlayrı argümanlar olarak alacak. perlGelmez değil Tırnakları görürler olarak kabuk onları kaldırır .)

Ama şimdi, dahause strict; önce Perl betiğinde yazmayı deneyinsay . Şimdi aynı hata ile başarısız oluyor rename:

$ perl -E 'use strict; say b1.DAT'
Bareword "b1" not allowed while "strict subs" in use at -e line 1.
Bareword "DAT" not allowed while "strict subs" in use at -e line 1.
Execution of -e aborted due to compilation errors.

Bu use strict;, Perl tercümanının barewordlara dize olarak davranmasını yasakladığı için oldu . Bu özel özelliği yasaklamak için, sadece subskısıtlamayı etkinleştirmek yeterli olacaktır . Bu komut yukarıdakiyle aynı hataları üretir:

perl -E 'use strict "subs"; say b1.DAT'

Ancak genellikle Perl programcıları sadece yazacak use strict;, bu da subskısıtlamayı ve diğer iki taneyi mümkün kılıyor . use strict;genellikle önerilen bir uygulamadır. Yani renamekomut için yapar sizin kodu. Bu yüzden bu hata mesajını alıyorsunuz.

4. Özetle, olan buydu:

  1. Kabuğunuz b1.DAT, renameher yol adı bağımsız değişkeni için bir döngüde çalışacak Perl kodu olarak işlem gören ilk komut satırı bağımsız değişkeni olarak geçti .
  2. Bu anlamlandı b1ve operatörle DATbağlantı kurdu ..
  3. b1ve işaretler DATile öneklenmediği için bareword olarak muamele gördüler.
  4. Bu iki eyersiz, yerleşik işlevlerin veya herhangi bir kullanıcı tanımlı alt yordamın adı olarak kabul edilirdi, ancak bu adların hiçbirinde bu tür şeyler yoktu.
  5. "Kesin subs" etkin olmasaydı, dize ifadeleri gibi ele alınır 'b1've 'DAT"birleştirilirdi". Bu, amaçladığınızdan çok uzak, bu özelliğin genellikle yararlı olmadığını aydınlatan.
  6. Çünkü "sıkı subs", etkinleştirilmiş renametüm sağlayan kısıtlamaları ( vars, refsve subs). Bu nedenle, bunun yerine bir hata var.
  7. renamebu hata nedeniyle çıkın. Bu tür bir hata erken gerçekleştiği için, siz geçmiş olmasanız bile, dosya yeniden adlandırma girişimi yapılmamıştır -n. Bu, kullanıcıları istemeden dosya adı değişikliklerinden ve hatta bazen gerçek veri kaybından koruyan iyi bir şeydir.

Bu cevabın daha önce yapılan bir taslağında birkaç önemli noktayı ele almama yardımcı olan Zanna'ya teşekkürler . O olmasaydı, bu cevap daha az mantıklı olurdu ve hiç gönderilmeyebilirdi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.