Bir boruyu nasıl eklerim | linux find -exec komutumda?


220

Bu işe yaramıyor. Bu bulmak için yapılabilir mi? Yoksa xargs'a ihtiyacım var mı?

find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;

Yanıtlar:


145

Boru sembolünü birden çok işlem yürütme talimatı olarak yorumlama ve bir işlemin çıktısını başka bir işlemin girişine aktarma işi kabuğun (/ bin / sh veya eşdeğeri) sorumluluğudur.

Örneğinizde, boruları şu şekilde gerçekleştirmek için en üst düzey kabuğunuzu kullanmayı seçebilirsiniz:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'

Verimlilik açısından, bu sonuç bir bulma çağrısına, çok sayıda zcat çağrısına ve bir agrep çağrısına mal olur.

Bu, çok sayıda zcat çağrısının ürettiği tüm çıktıları işleyecek olan tek bir agrep sürecinin ortaya çıkmasına neden olacaktır.

Herhangi bir nedenle agrep'i birden çok kez çağırmak istiyorsanız, şunları yapabilirsiniz:

find . -name 'file_*' -follow -type f \
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh

Bu, yürütmek için borular kullanarak komutların bir listesini oluşturur, ardından bunları gerçekten yürütülecek yeni bir kabuğa gönderir. (Son "| sh" yi atlamak, böyle komut satırlarının kuru çalışmalarını hata ayıklamak veya gerçekleştirmek için iyi bir yoldur.)

Verimlilik açısından, bu sonuç bir bulma çağrısına, bir sh çağrışmasına, çok sayıda zcat çağrısına ve çok sayıda agrep çağrısına mal olur.

Komut çağırma sayısı açısından en etkili çözüm Paul Tomblin'in önerisidir:

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

... bir keşif çağrısı, bir xargs çağrısı, birkaç zcat çağrısı ve bir agrep çağrısı maliyeti.


1
Xargs'ın bir başka avantajı, -P anahtarını (-P 0) kullanarak modern çok çekirdekli işlemci ile daha da hızlandırabilmenizdir.
flolo

Evet, -P swich gerçekten de genel olarak uygulamayı hızlandırmanın güzel bir yoludur. Ne yazık ki, paralel zcat işlemlerinin çıktısının agrep serpiştirilmiş içine aktarılması riskini çalıştırıyorsunuz, bu da sonucu etkileyecektir. Bu etki kullanılarak gösterilebilir: echo -e "1 \ n2" | xargs -P 0 -n 1 evet | uniq
Rolf W. Rasmussen

@Adam, önerdiğiniz değişikliği yaptım.
Paul Tomblin

bunun için görkemli xjobs komutunu (başlangıçta Solaris'ten)
yükleyebilirsiniz

4
Daha basit ve daha genel bir cevap olan stackoverflow.com/a/21825690/42973 : -exec sh -c "… | … " \;.
Eric O Lebigot

279

çözüm kolaydır: sh ile çalıştırın

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \;

17
OP'nin neyi başarmaya çalıştığı yukarıdaki önerilerle karşılanabilir, ancak aslında sorulan soruya cevap veren budur. Bunu bu şekilde yapmak için nedenler var - exec, özellikle testle birleştirildiğinde find tarafından döndürülen dosyalar üzerinde çalışmaktan çok daha güçlü. Örneğin: geda-gaf / -type d -exec bash -c 'DIR = {}; [[$ ($ DIR -maxdepth 1 | xargs grep -i spice | wc -l) -ge 5]] && echo $ DIR '\; Arama yolunda, spice kelimesini içeren dizindeki tüm dosyalar arasında toplamda 5'ten fazla satır içeren tüm dizinleri döndürür
swarfrat

3
En iyi cevap. Çıktının tamamını kullanmak (diğer yanıtların önerdiği gibi), her dosyadaki grep ile aynı değildir. İpucu: sh yerine, istediğiniz başka bir kabuk kullanabilirsiniz (bunu bash ile denedim ve tamam çalışıyor).
pagliuca

1
-cSeçeneği göz ardı etmediğinizden emin olun . Aksi takdirde kafa karıştırıcı bir No such file or directoryhata mesajı alırsınız.
asmaier

işlenen bir kabuk içinde bulmayı kullanan harika bir ps değiştirme: / usr / bin / find / proc -mindepth 1 -maxdepth 1 -type d -regex '. * / [0-9] +' - print -exec bash -c "kedi {} / cmdline | tr '\\ 0' ''; echo" \;
parity3

1
Düzenli ifade kullanarak dosya bulma ve sed ile yeniden adlandırma örneğifind -type f -name '*.mdds' -exec sh -c "echo {} | sed -e 's/_[0-9]\+//g' | xargs mv {}" \;
Rostfrei

16
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

Verimlilik nedeniyle baskı ve xargs kullanmaktan kaçınmayı umuyoruz. Belki de bu benim sorunum: find -exec aracılığıyla borulu komutları işleyemiyor
someguy

Bu, adlarında boşluk bulunan dosyalarla çalışmaz; düzeltmek, -print'i -print0 ile değiştirmek ve -0 seçeneğini xargs'a eklemek
Adam Rosenfield

2
@someguy - Ne? Verimlilik nedeniyle xargs'tan kaçınmak mı? Bir zcat örneğini çağırmak ve birden çok dosya listesini iletmek, bulunan her dosya için yeni bir örneğini yürütmekten çok daha etkilidir.
Sherm Pendley

@Adam - Önerilen değişikliğinizi yaptım. Bulunduğum zamanın% 99'u, kaynak kod dizinlerimde ve hiçbir dosyanın boşlukları olmadığı için print0 ile uğraşmıyorum. Şimdi belgeler dizini ise, print0 hatırlıyorum.
Paul Tomblin

10

Bulunan whiledosya üzerinde birden çok eylem gerçekleştirebilen bir döngüye findyöneltebilirsiniz. Yani burada bakarak için biridir jarbüyük bir dağıtımla olan klasördeki belirli bir java sınıfı dosyası için arşivler jardosyaları

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done

kilit nokta, whiledöngünün noktalı virgülle ayrılmış dosya adında atıfta bulunan birden fazla komut içermesidir ve bu komutlar dikey çizgi içerebilir. Bu örnekte, eşleşen dosyanın adını yankılayıp belirli bir sınıf adı için arşiv filtrelemede ne olduğunu listeliyorum. Çıktı şöyle görünür:

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2.0.M20090902-0800 .jar org / eclipse / core / databinding / gözlemlenebilir / list / IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar / usr / lib / eclipse / plugins / org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar / usr / lib / eclipse / plugins / org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

bash kabuğumda (xubuntu10.04 / xfce) gerçekten eşleşen sınıf adını fgrep, eşleşen dizeyi vurgularken kalın yapar ; bu, jararanan yüzlerce dosyanın listesini taramayı ve eşleşmeleri kolayca görmeyi gerçekten kolaylaştırır .

Windows'da aynı şeyi aşağıdakilerle yapabilirsiniz:

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList

pencerelerde komut ayırıcısının '&' değil 'olduğunu unutmayın; ve '@' komutunun yankısını bastırır; tıpkı linux yukarıdaki çıktıyı buluyor gibi düzenli bir çıktı verir; her ne kadar findstreşleşen dize kalın yapmaz, bu yüzden eşleşen sınıf adını görmek için çıktı biraz daha yakından bakmak zorunda. 'For' komutunun pencerelerinin, metin dosyaları arasında döngü yapmak gibi birkaç püf noktası bildiği ortaya çıkıyor ...

zevk almak


2

Ben bir dize kabuk komutu (sh -c) çalışan en iyi, örneğin bulundu:

find -name 'file_*' -follow -type f -exec bash -c "zcat \"{}\" | agrep -dEOE 'grep'" \;

0

Basit bir alternatif arıyorsanız, bu bir döngü kullanılarak yapılabilir:

for i in $(find -name 'file_*' -follow -type f);do zcat $i | agrep -dEOE 'grep');done

veya daha genel ve anlaşılması kolay bir form:

for i in $(YOUR_FIND_COMMAND);do YOUR_EXEC_COMMAND_AND_PIPES );done

ve YOUR_EXEC_COMMAND_AND_PIPES içindeki {} ile $ i değerini değiştirin

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.