.Txt dosyası yoksa kabukta * .txt ile genişletme çalışmaz


10

Genişleme ile oynuyordum ve tuhaf bir davranış fark ettim. Yapmayı denedim:

echo ./*.txt

Geçerli dizinimde .txt dosyası yoktu. Aldığım çıktı:

./*.txt

Sadece merak ediyorum: Bunu neden aldım? Çıktı almamayı bekliyordum.

Not: Bir dosyam olduğunda .txt, genişletme doğru yorumlandı. Başka bir deyişle, bir smthn.txtdosyam olduğunu varsayalım, yankı aslında yankılanıyordu current_directory/smthn.txt.

Yanıtlar:


15

Bash shell man sayfasından uyarlama,

bash her kelimeyi *,? ve [karakterleri için tarar. Bu karakterlerden biri belirirse, kelime bir desen olarak kabul edilir ve yerine, desenle eşleşen alfabetik olarak sıralanmış bir dosya adı listesi gelir. Eşleşen dosya adı bulunamazsa ve nullglob kabuk seçeneği etkin değilse, sözcük değiştirilmez. Nullglob seçeneği ayarlanırsa ve hiçbir eşleşme bulunamazsa, sözcük kaldırılır.

Bu durumda nullglob'un etkin olmadığını varsayalım, bu yüzden kelime değişmeden kalır - dolayısıyla gördüğünüz çıktı.


2
Davranışı aşağıdaki gibi değiştirebilirsiniz: shopt -s nullglobeşleşmeyen desenler için boş dizeler verir ve shopt -u nullglob(standart ayar) desenin kendisini verir.
PerlDuck

13

Çıktı almamayı bekliyordum.

Eğer nullglobvarsayılan vardı o komutları durumunda tedavi olduğu (belki maalesef) yaygındır, çünkü birçok komutlar, hiç beklenmedik bir şekilde davranır sıfır olması durumunda daha niteliksel olarak farklı bir şekilde dosya adı argümanları bir veya daha fazla dosya argümanları.

Etkinleştirdiğinizi nullglob( shopt -s nullglob) ve hiçbir dosyanın eşleşmediği bir dizinde olduğunuzu varsayalım *.txt. O *.txtzaman gerçekten boş bir alan değil, hiç alan yok - beklediğiniz gibi hiçbir şeye genişleyemez. Ancak bunun şu sonuçları olacaktır:

  • ls *.txtgeçerli dizindeki tüm dosyaları listeler (gizli dosyalar hariç), çünkü lsherhangi bir dosya adı argümanı iletmediğinizde olan budur.
  • cat *.txtdan okurdum standart girdi çünkü ne zaman, cathiçbir dosya adı değişkenleri olduğu, bu koştum sanki bulunuyor cat -. Etkileşimli olarak çalışıyorsa, girdi beklemek etrafında oturur. Birçok komut bu şekilde davranır.
  • cp *.txt dest/hata ile başarısız olur cp: missing destination file operand after 'dest/'. Bu bir felaket değil, ancak kafa karıştırıcı ve muhtemelen istenen sessiz başarıdan oldukça farklı.
  • file *.txtve sıfır dosya adı bağımsız değişkenleri durumunda özel davranışı olmayan diğer çeşitli programlar, hiçbiri iletilmediğinde yine de hata veya kullanım iletisiyle başarısız olur.
  • Sezgisel olarak sık sık çalışması gerektiği gibi hisseden durumlar bile olmaz. hiçbir şey yerine printf 'Got file: "%s"\n' *.txtyazdırır Got file: "".
  • Tekrarlarını alıntı Kaza yetmezliği *, ?ve [o değildir ama anlamaya zor olabilir yollarla daha sık açıkça yanlış sonuçlar üretecektir kabuk tarafından genişletilmiş üzere tasarlanmıştır. Örneğin, geçerli dizinde hiçbir dosya adı başlatılmazsa gedit, apt list gedit*( apt list 'gedit*'amaçlanan yerde ) adil olur apt listve kullanılabilir tüm paketleri listeler .

Bu nedenle, bu davranışı talep etmeden almamanız iyi olur. Muhtemelen aslında basitleştirilmiştir en yaygın pratik durum nullglobolduğunu for f in *.txt. Bu soruya da bakınız ( Sergiy Kolodyazhnyy'nin cevabı bağlantılıdır).

failglobYanıtlanması daha zor olan soru - herhangi bir dosyayla eşleşmeyen bir glob'a sahip olmanın bir genişleme hatası - bash'da varsayılan değil. Sergiy Kolodyazhnyy'nin cevabının , doğrudan hitap etmeden bile bunun nedenini yakaladığına inanıyorum . Genişlemeyen glob'ları bir genişleme hatası üretmeden tutmak (belki de maalesef) standart davranıştır ve aynı zamanda geleneksel ve dolayısıyla beklenen davranıştır. Bash, adla çağrılmadığı shveya --posixseçeneği geçmediği sürece tam olarak POSIX uyumlu olmaya çalışmasa da, POSIX modunda olmasa bile tasarım seçeneklerinin çoğu doğrudan POSIX'i izler. Bazı davranışlar seçmek zorunda kaldılar ve kullanıcıların beklentilerine karşı çıkmanın olumsuz yanları var.


Sanırım bu, konunun tarihsel olarak en az etkili yönüdür, bu yüzden son olarak kurtardım ... ancak nullglobdavranış hakkında kavramsal olarak biraz garip bir şey olduğunu belirtmek gerekir .

nullglobilk bakışta zarif görünüyor çünkü sözdizimsel olarak , sıfır eşleme dosyalarına bir, iki veya başka bir sayıdan farklı davranmıyor. Globların argümanlara dönüştüğü çalıştırdığımız komutlar , yukarıda açıklandığı gibi aynı davranma eğiliminde değildir . Ama sözdizimsel olarak bu en azından doğru hissettiriyor, bence sorunuzun motivasyonu.

Ve yine de, nullglobaslında yükseltmediği - ele almayan başka, daha ince bir tutarsızlık var . Durumunda sıfır globbing karakterler ( "joker") bir ya da iki ya da herhangi bir başka sayıda bundan derece farklı muamele edilmektedir. Örneğin, birlikte shopt -s nullglobeğer ab?d?fherhangi bir dosya uymuyor, bu çıkarılır; eğer ab?dherhangi bir dosya uymuyor, bu çıkarılır; ancak abherhangi bir dosyayla eşleşmezse (yani, adı tam olarak olan bir dosya yoksa ab) yine de kaldırılmaz. Elbette, kaldırılsaydı bir felaket olurdu, çünkü mevcut dizindeki mevcut bir dosyaya hiç atıfta bulunulmayabilir; bir dosyaya atıfta bile bulunmayabilir. Ancak bu, toplam tutarlılık umudunu hala ortadan kaldırmaktadır.

Bash'ın sağladığı üç davranış - herhangi bir dosyayla eşleşmeyen globları, sanki glob değilmiş gibi ele alıp genişlemeden geçirme varsayılanı, bunları tedavi etmeyi beklediğiniz davranış (eğer bu tek kelime öbeğini affederseniz) eşleşen dosyaların tüm sıfırı ( nullglob) ve hataları dikkate failglobalmanın güvenli davranışını ( ) belirtmek olarak - tümü, belirli bir sözcüğün bir amaç olarak tasarlanıp tasarlanmadığını bilememek için kabuğun doğasında bulunan belirsizliğe farklı yaklaşımları temsil eder. dosya adı. Kabuk genişletmelerini, onunla çağırdığınız belirli komutların argümanlarını nasıl ele alacağına dair bilgi sahibi olmadan gerçekleştirir.

Bu, endişelerin ayrılmasının birçok örneğinden biridir . Tasarımı Unix felsefesini takip eden sistemlerde, her bölüm bir şey yapmayı ve iyi yapmayı amaçlamaktadır . Kabuk, metni komutlara ve bağımsız değişkenlere işler ve çoğu kabuğun dışında olan bu komutları çağırır. Bu dış komutlarıdır sistemlere göre daha çok yönlü çok daha güzel olacak ve eğilimi kendilerini (DOS ve Windows geleneksel komut işlemciler gibi) Bu dönüşümleri gerçekleştirmek için sorumlu. Ama ara sıra dezavantajları var.


Görünüşe göre, bash-4.3.39 (2) sahip değil failglob. Bu yüzden her zaman desteklenmediği için varsayılan olamaz.
Ruslan

6

Ana nedeni olan bu tarafından belirtilen standart davranıştır çünkü POSIX'e - (gibi kabukları kapakları komut dili kabuk ve diğer şeyler desen eşleştirme arasında standart bash, dash- Ubuntu'nun varsayılan kabuk /bin/shve kshbu standardı izleyin). Bölüm 2.13.3 Dosya Adının Genişletilmesi için Kullanılan Desenler :

Desen, mevcut dosya adları veya yol adlarıyla eşleşmezse, desen dizgisi değişmeden bırakılır.

Bu elbette bir yan etkiye sahiptir - tam anlamıyla olabilecek bir dosya adı *.txt. nullglobSeçeneğini bashve zshkutu yardımı: Bu seçenek aracılığıyla etkin olup olmadığını shopt -s nullglobeşleşen dosya adları bulunca (ve bu soruya geçerli olduğu varsayılan olarak etkin değildir), sonra globstar boş dizeye genişletilecektir. ksh93aynı etkiyi sağlayan kendi gelişmiş desen eşleştirme mekanizmasına sahiptir~(N)*.txt

Ayrıca bkz. Nullglob neden varsayılan değil?

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.