Dosya adı boşluk içerdiğinde find'ı nasıl kullanabilirim?


17

Dosya adlarını diğer programlara aktarmak istiyorum, ancak adlar boşluk içerdiğinde boğuluyorlar.

Diyelim ki adlı bir dosyam var.

foo bar

findDoğru adı nasıl iade edebilirim ?

Açıkçası istiyorum:

foo\ bar

veya:

"foo bar"

EDIT : Ben geçmek istemiyorum xargs, ben doğru bir şekilde biçimlendirilmiş bir dize dışarı almak istiyorum findböylece dosya adları dizesini doğrudan başka bir programa boru olabilir.


5
neye bağlıyorsun? -execBayrağın farkında findmısın? potansiyel olarak bu hatayı hafifletebilir ve -execdiğer komutlara iletmek yerine komutunuzu daha verimli hale getirebilirsiniz . Sadece benim $ .02
h3rrmiller

6
@bug: finddosya adlarını iyi biçimlendirir; her satıra bir isim yazılır. (Tabii ki, bir dosya adı yeni satır karakteri içeriyorsa bu muğlaktır.) Sorun, alan aldığında alıcı son "boğulma" dır; bu, anlamlı bir cevap istiyorsanız bize alıcı sonun ne olduğunu söylemeniz gerektiği anlamına gelir. .
rici

2
"Düzgün biçimlendirilmiş" olarak adlandırdığınız şey gerçekten "kabuk tarafından tüketilmek üzere kaçar". Bir grup dosya adını okuyabilen çoğu yardımcı program, kabuktan kaçan bir ad üzerinde boğulur, ancak aslında finddosya adlarının kabuk için uygun bir formatta çıktı alma seçeneği sunması mantıklı olur . Bununla birlikte, genel olarak, -print0GNU finduzantısı diğer birçok senaryo için de iyi çalışır ve bunu her durumda kullanmayı öğrenmelisiniz.
tripleee

2
@bug: Bu arada, ls $(command...)listeyi beslemiyor stdin. $(command...)Doğrudan çıktısını komut satırına koyar . Bu durumda, $IFSc'den okunan kabuktur ve çıktının nasıl bölüneceğine karar vermek için şu anki değerini kullanır . Genel olarak, kullanmanız daha iyi olur xargs. Bir performans artışı fark etmeyeceksiniz.
rici

2
find -printf '"%p"\n'bulunan her adın başına çift tırnak ekler, ancak dosya adındaki çift tırnak işaretlerini doğru şekilde tırnak içine almaz. Dosya adlarınızda gömülü çift tırnak işareti yoksa, sorunu yok sayabilirsiniz: veya üzerinden geçebilirsiniz sed 's/"/&&/g;s/^""/"/;s/""$/"/'. Dosya adlarınız kabuk tarafından işleniyorsa, büyük olasılıkla çift tırnak yerine tek tırnak kullanmalısınız (aksi takdirde sweet$HOMEböyle bir şey olur sheet/home/you). Ve bu hala içinde yeni satır bulunan dosya adlarına karşı çok sağlam değil. Bunlarla nasıl başa çıkmak istiyorsun?
tripleee

Yanıtlar:


18

POSIXLY:

find . -type f -exec sh -c '
  for f do
    : command "$f"
  done
' sh {} +

İle finddesteklerin -print0ve xargsdestekler -0:

find . -type f -print0 | xargs -0 <command>

-0 seçeneği xargs'e dosya adlarını sonlandırmak (ayırmak) için boşluk yerine ASCII NUL karakterini kullanmasını söyler.

Misal:

find . -maxdepth 1 -type f -print0 | xargs -0 ls -l

Çalışmıyor. Ben çalıştırdığınızda ls $(find . -maxdepth 1 -type f -print0 | xargs -0)alıyorum ls: cannot access ./foo: No such file or directory ls: cannot access bar: No such file or directory
hata

1
Gnouc'un gerçekten yazdığı şekilde denediniz mi? Eğer bunu yapmak için ısrar ediyorsanız $(..), çift tırnak içine "$(..)"
almayı

3
@bug: komutunuz yanlış. Tam olarak Worte deneyin ve manpage okumak findve xargs.
cuonglm

Anlıyorum, sonra yine doğrudan boru olabilir biçimlendirilmiş bir dize almak istiyorum.
hata

1
@bug: Sadece xargs -0 <programınız> kullanın
cuonglm

10

Kullanmak -print0bir seçenektir, ancak tüm programlar nullbyte sınırlandırılmış veri akışlarının kullanımını desteklemez, bu nedenle Gnouc'un cevabına göre bazı şeyler xargsiçin -0seçenekle birlikte kullanmanız gerekir .

Alternatif kullanım olacaktır find's -execveya -execdirseçenekler. Aşağıdakilerden ilki dosya adlarını somecommandbirer birer beslerken ikincisi bir dosya listesine genişleyecektir:

find . -type f -exec somecommand '{}' \;
find . -type f -exec somecommand '{}' +

Birçok durumda globbing kullanmaktan daha iyi olduğunuzu görebilirsiniz. Modern bir kabuğunuz varsa (bash 4+, zsh, ksh), globstar( **) ile özyinelemeli globbing alabilirsiniz . Bash'da bunu ayarlamanız gerekir:

shopt -s globstar
somecommand ./**/*.txt ## feeds all *.txt files to somecommand, recursively

shopt -s globstar extglobBenim .bashrc söyleyerek bir satır var , bu yüzden bu benim için her zaman etkin (ve böylece de yararlı olan genişletilmiş globs).

Özyinelemeyi istemiyorsanız ./*.txt, çalışma dizinindeki her * .txt dosyasını kullanmak için açıkça kullanın . findbazı yararlı ayrıntılı arama özelliklerine sahiptir ve on binlerce dosya için zorunludur (bu noktada kabuğun maksimum argüman sayısına gireceksiniz), ancak günlük kullanım için genellikle gereksizdir.


Hey @evilsoup {} bu komut dosyasında ne yapıyor?
Ayusman

3

Şahsen, -execbu tür bir sorunu çözmek için bulma eylemini kullanırdım. Veya gerekirse xargsparalel yürütmeye izin verir.

Ancak, findbash tarafından okunabilen bir dosya adı listesi elde etmenin bir yolu vardır . Şaşırtıcı değil, kullandığı -execve bashözellikle bir uzantısı, printfkomuta:

find ... -exec bash -c 'printf "%q " "$@"' printf {} ';'

Bununla birlikte, bu kabuktan kaçan sözcükleri doğru bir şekilde yazdıracak olsa da $(...), $(...)tırnak işaretleri veya kaçışları yorumlamadığı için ile birlikte kullanılamaz . (Başlangıcı $(...)tırnak işareti içine alınmadıkça kelime bölme ve yol adı genişletme işlemine tabidir.) Dolayısıyla aşağıdakiler istediğinizi yapmayacaktır:

ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)

Yapmanız gerekenler:

eval "ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)"

(Yukarıdaki canavarlığı test etmek için gerçek bir girişimde bulunmadığımı unutmayın.)

Ama sonra şunları da yapabilirsiniz:

find ... -exec ls {} +

lsSenaryonun OP'nin kullanım durumunu yeterince yakaladığını düşünmüyorum , ancak bu sadece spekülasyon, çünkü aslında ne yapmaya çalıştığı gösterilmedi. Bu çözüm aslında çok iyi çalışıyor; Ben de dahil olmak üzere, denedim tüm komik dosya adları için beklenen (belirsiz) çıktı olsuntouch "$(tr a-z '\001-\026' <<<'the quick brown fox jumped over the lazy dogs')"
üçlü

@triplee: OP'nin ne yapmak istediğine dair hiçbir fikrim yok. Alıntılanan dizgiyi iletmek için evalyapmanın tek gerçek avantajı, evalhenüz geçmemenizdir; bir parametreye kaydedebilir ve daha sonra, belki de birkaç kez farklı komutlarla kullanabilirsiniz. Bununla birlikte, OP, kullanım durumu olduğuna dair hiçbir belirti vermez (ve eğer olsaydı, dosya adlarını bir diziye koymak daha iyi olabilir, ancak bu da zor.)
rici

0
find ./  | grep " "

dosyaları ve dizinleri alır boşluk içerir

find ./ -type f  | grep " " 

dosyaları içerecek boşluklar içerir

find ./ -type d | grep " "

dizinler boşluk içerecek size alacak


-2
    find . -type f -name \*\  | sed -e 's/ /<thisisspace>/g'

Bu ilginç bir yanıt, ama bu sorunun cevabı değil.
Scott
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.