Bulmak neden bazen komut satırı yolu bağımsız değişkeniyle eşleşiyor?


9

Linux'ta,

cd /tmp
mkdir foo; cd foo

Şimdi koşuyor

find . -name 'foo'

çıktı vermez. Halbuki Koşarken

find /tmp/foo -name 'foo'

/tmp/fooBana mantıklı olmayan bir çıktı verir . Birisi nedenini açıklayabilir mi?


2
belirtildiği gibi verilen yolun içindeki seaches'i bulun . Giriş yaparsanız ./eşleşmezfoo
Costas

@Costas: Bunu anlıyorum. Anlamadığım şey, mutlak yolu verirseniz neden fark yarattığıdır find.
York

@York Bazı durumlarda her zaman doğru olan davranış yoktur. Arama yolunun dışındaki barbir dosyaya işaret eden ada sahip bir sembolik bağlantı düşünün foo. Eşleşecek mi yoksa olmayacak mı?
Hauke ​​Laging

1
.Ve /tmp/fooaynı değildir - bunlar aynı dizine iki farklı sabit bağlantılar vardır; find /tmp/foo/. -name 'foo'hiçbir şey bulamaz.
jimmij

@jimmij: koştuğumda, bash'tan find /tmp/foo -name 'foo'dizinde /tmp/foo, adı "foo" olan bir dosya bulmasını istiyordum . Dizin /tmp/fooboş olduğu için hiçbir şey döndürmemiş olmalıdır. Neden geri döndüğünü anlamıyorum /tmp/foo. Öte yandan, find . -name 'foo'koştuğumda, bash'a aynı şeyi soruyordum, yani, geçerli dizinde (olduğu gibi /tmp/foo), adı 'foo' olan bir dosya buluyordum ve mantıklı olan hiçbir şey döndürmüyor.
York

Yanıtlar:


15

findbelirtilen dizin ağaç (lar) ını geçer ve bulduğu her dosya için verilen ifadeyi değerlendirir. Geçiş verilen yolda başlar. İşte nasıl find . -name fooçalıştığının bir özeti :

  • Komut satırındaki ilk yol: .
    • Temel ad ( .) kalıpla eşleşiyor foomu? Hayır, hiçbir şey yapma.
      Bu /tmp/fooaynı dizin için başka bir isim olur . Ama findbunu bilmiyor (ve bulmaya çalışması gerekmiyor).
    • Yol bir dizin mi? Evet, çaprazlayın. İçindeki girişleri numaralandırın .ve her bir giriş için geçiş işlemini gerçekleştirin.
      • Dizin boş şudur: başka hiçbir girdi içerir .ve ..hangi findyinelemeli geçiş vermez. Yani iş bitti.

Ve find /tmp/foo:

  • Komut satırındaki ilk yol: /tmp/foo
    • Temel ad ( foo) kalıpla eşleşiyor foomu? Evet, bu yüzden durum eşleşir.
      • Bu koşulla ilişkili bir işlem yoktur, bu nedenle yolu yazdırmak için varsayılan eylemi gerçekleştirin.
    • Yol bir dizin mi? Evet, çaprazlayın. İçindeki girişleri numaralandırın /tmp/foove her bir giriş için geçiş işlemini gerçekleştirin.
      • Dizin boş şudur: başka hiçbir girdi içerir .ve ..hangi findyinelemeli geçiş vermez. Yani iş bitti.

Öyle olur .ve /tmp/fooaynı dizindir, ancak findher ikisinde de aynı davranışa sahip olduğunu garanti etmek için yeterli değildir . findKomut aynı dosyaya yolları arasında ayrım yolu vardır; -nameyüklem bunlardan biridir. find /tmp/foo -name foobaşlangıç ​​dizini ve altındaki tüm dosyalar ile eşleşir foo. find . -name .yalnızca başlangıç ​​diziniyle eşleşir ( .yinelemeli geçiş sırasında asla bulunamaz).


msgstr ",. ve .. dışında, yinelemeli olarak geçmeyen bir girdi içermiyor." "Özyinelemeli enine değil" anlamına gelir ".." bakın. Bu doğruysa, ".." bağlamında "enine özyinelemeli" ne anlama gelir?
Faheem Mitha

@FaheemMitha “değil çapraz yinelemeli yok” için geçerlidir .ve ... (Eğer findgeçilen .yinelemeli, tekrar ve tekrar ve tekrar dizine geçiyor sona edilmiş ...) .ve ..onlar dizin girdileri gibi görünür, sadece özel gösterimler değildir.
Gilles 'SO- kötü olmayı bırak

5

Testler uygulanmadan önce komut satırı bağımsız değişkenlerinin normalleştirilmesi yoktur. Bu nedenle sonuçlar kullanılan yola bağlı olarak değişir (sembol bağlantıları varsa):

cd /tmp
mkdir foo
ln -s foo bar
find /tmp/foo -name foo
find /tmp/bar -name foo

"Sizin durumunuzda" her iki çağrı da (daha fazla) kafa karıştırıcı olabilecek aynı sonucu verecektir. -mindepth 1Başlangıç ​​noktalarının göz ardı edilmesini istiyorsanız kullanabilirsiniz (POSIX olmayabilir).


-mindepth 1İşler. Yine de nedenini anlamıyorum find . -name 'foo've find /tmp/foo -name 'foo'farklı davranıyorum.
York

2

(gnu) find komutu, komut dosyasına sağlanan yol içinde bulunan tüm eşleşmeleri gösterir, çünkü komut satırı bağımsız değişkenleriyle karşılaştırmaya başlar, oradan dizin yapısına daha derin iner (böylece, -maxdepth 0testleri yalnızca temel düzeyle veya komut satırı bağımsız değişkenleriyle sınırlar. -mindepth 1komut satırı bağımsız değişkenlerini man findaçıkladığı gibi atlar ). find /tmp/foo -name 'foo'Dizinin kendisi boş olsa bile bir eşleşme vermenin nedeni budur .

find . -name 'foo'Öte yandan .(nokta), aynı inode ile bir hardlink gibi davranan özel bir dosya olduğu için herhangi bir sonuç vermeyecektir /tmp/foo- ayrı bir (özel olsa da) dosya adı gibidir ve sembolik bir bağlantı veya maruz kalan bir ifade değildir. kabuk tarafından yol adı genişletmesi. Bu nedenle, find tarafından verilen örnekteki komut satırı argümanlarına uygulanan ilk test hiçbir eşleşme göstermeyecektir, çünkü .gerçekten de tanımlanan ad modeliyle eşleşmez -name 'foo'. Ayrıca, /tmp/foo/.bir -namepatern testi yalnızca yolun taban adında gerçekleştirildiğinden (bkz. man find), Burada tekrar olan ..

Bu davranış beklenmeyebilir veya kullanıcı açısından sezgisel görünebilir (ve evet, ilk başta da kafam karıştı), bir hata oluşturmaz, ancak adam ve bilgi sayfalarında açıklanan mantık ve işlevselliğe karşılık gelir. gnu) bulmak.


0

Gilles'in cevabını yorumlamayı denedim, ama bir yoruma sığmayacak kadar uzundu. Bu nedenle, kendi soruma cevap olarak koyuyorum.

Gilles'in açıklaması (ve Shevek'in de) açık ve mantıklı. Buradaki kilit nokta, sadece findverilen yolların içindeki dosyaların adlarını (özyinelemeli olarak) eşleştirmeye çalışmakla kalmaz, aynı zamanda verilen yolların temel adıyla da eşleşmeye çalışır.

Öte yandan, findbir hata olmaktan ziyade, çalışma şeklinin bu olduğuna dair herhangi bir kanıt var mı? Kanımca, sonuçları tutarsız yapmazsa find .ve find ABSOLUTE-PATHtutarsızlık her zaman kafa karıştırıcıdır ve geliştiriciyi "neyin yanlış olduğunu" anlamaya çalışmak için çok fazla zaman harcayabilirse daha iyi olur . Benim durumumda bir senaryo yazıyordum ve yol bir değişkenden alındı. Bu yüzden senaryomun düzgün çalışması için yazmayı düşünebileceğim şey find $path/. -name 'pattern'.

Son olarak, devam etmeden önce findher zaman .geçerli dizini ile değiştirerek tutarlı sonuçlar elde etmek düşünüyorum .


-1

fooGöreli aramayı başlattığınız dizinde adlandırılmış bir nesne yok .

Mutlak adı bir başlangıç ​​dizini olarak kullanırken gfindraporladığında buggy olduğunu varsayarak haklısınız /tmp/foo.

GfindStandarttan farklı sapmalara sahip, başka bir tane bulduğunuz anlaşılıyor. Daha standart uyumlu bir çözümü sevdiğinizde, sfindbunun bir parçası olmasını tavsiye ederim schilytools.

-namedizin arama sonuçları için geçerlidir. Bahsettiğiniz iki durumdan hiçbiri foobir readdir()işlemden bir dizin girdisi döndürmez .


Bunun da bir hata olduğundan şüpheleniyorum. İşte çıktı find --version: find (GNU findutils) 4.4.2 Telif Hakkı (C) 2007 Free Software Foundation, Inc. Lisansı GPLv3 +: GNU GPL sürüm 3 veya üstü < gnu.org/licenses/gpl.html >
York

Örnek komutlarınızı find(POSIX sertifikalı) ile kontrol ettim gfindve sfind; sorun yalnızca kullandığınızda oluşur gfind. Linux'ta, gfindyerel adı altında değil, adı altında yüklenir find.
schily

3
find /tmp/foo -name fooÇıktı için doğrudur /tmp/foo. (Cc @York) Bu OpenBSD find, GNU find, BusyBox find, Solaris findve diğer POSIX uyumlu davranışlardır find(“İncelenen dosya adının taban adı desen (…) ile eşleşiyorsa birincil birincil olarak değerlendirilir ” - dosya adı yol işlenen olarak geçirilen, hiçbir readdirarama yapılmaz ).
Gilles 'SO- kötü olmayı bırak'
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.