birden çok komutla -exec'i bul


430

Ben find -exec birden fazla komut ile herhangi bir başarı olmadan kullanmaya çalışıyorum. Aşağıdakiler gibi komutların mümkün olup olmadığını bilen var mı?

find *.txt -exec echo "$(tail -1 '{}'),$(ls '{}')" \;

Temel olarak, geçerli dizindeki her txt dosyasının son satırını yazdırmaya ve satırın sonuna, virgül ve arkasından dosya adına yazdırmaya çalışıyorum.



1
Komutun olasılığını kontrol ettikçe, sisteminizde denemediniz mi?
Sriram

1
Gönderen findmanuel sayfa: There are unavoidable security problems surrounding use of the -exec option; you should use the -execdir option instead.unixhelp.ed.ac.uk/CGI/man-cgi?find
JVE999


@ JVE999 bağlantısı kopuk, alternatif ss64.com/bash/find.html adresinde
Keith M

Yanıtlar:


659

find-execkomuta birden fazla bölüm kabul eder . Örneğin:

find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;

Bu durumda ikinci komutun yalnızca ilk komutun @Caleb tarafından belirtildiği gibi başarılı bir şekilde dönmesi durumunda çalışacağını unutmayın. Her iki komutun da başarılarına veya başarısızlıklarına bakılmaksızın çalışmasını istiyorsanız, bu yapıyı kullanabilirsiniz:

find . -name "*.txt" \( -exec echo {} \; -o -exec true \; \) -exec grep banana {} \;

nasıl iki kez grep? bu başarısız oluyor: find ./* -exec grep -v 'SOĞUK,' {} \; -exec egrep -i "my_string" {} \;
rajeev

51
@rajeev İkinci yürütme işlemi yalnızca ilk döndürülen başarının dönüş kodu başarılı olursa çalışır, aksi takdirde atlanır. Bu muhtemelen bu cevapta belirtilmelidir.
Caleb

1
Bu cevap olurdu
pylover

1
Kullanımına dikkat -ndiğer bazı yanıtlar ikinci komut çıktısının sadece bir satır üretir ve bunları daha kolay okunur olmasını istiyorsanız kullanışlı yankı tarafından oluşturulan yeni satır, bastırmak için de.
William Turrell

Harika bir çözüm. Tıkır tıkır çalışıyor.
Philippe Delteil


52

Aşağıdakilerden biri:

find *.txt -exec awk 'END {print $0 "," FILENAME}' {} \;

find *.txt -exec sh -c 'echo "$(tail -n 1 "$1"),$1"' _ {} \;

find *.txt -exec sh -c 'echo "$(sed -n "\$p" "$1"),$1"' _ {} \;

12
{} Öncesindeki alt çizgi ne için?
qed

2
@qed: Yerini tutan bir uzaklaşma değeridir $0. Bunu "_" yerine "foobar" ile deneyin: find /usr/bin -name find -exec sh -c 'echo "[$0] [$1]"' foobar {} \;- çıktı: "[foobar] [/ usr / bin / find]".
sonraki duyuruya kadar duraklatıldı.

1
@XuWang: Evet, böyle olduğunu söyleyebilirim. Bildiğiniz gibi $0, genellikle program adıdır ( ARGV[0]).
sonraki duyuruya kadar duraklatıldı.

3
Bu yöntem için, iletilen komut dosyasının sh -cçift ​​tırnak içinde değil, tek tırnak içinde olması önemlidir . Aksi takdirde $1yanlış kapsamdadır.
Nick

1
@Nick tırnakların bununla hiçbir ilgisi yoktur - '$1'değişkenten ( "\$1") kaçtığınız sürece çift tırnak ile yazabilirsiniz . Diğer karakterlerden de kaçabilirsiniz ( "\"").
Camilo Martin

22

Başka bir yol şöyle:

multiple_cmd() { 
    tail -n1 $1; 
    ls $1 
}; 
export -f multiple_cmd; 
find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;

bir satırda

multiple_cmd() { tail -1 $1; ls $1 }; export -f multiple_cmd; find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;
  • "multiple_cmd() " - bir işlevdir
  • "export -f multiple_cmd " - diğer alt kabukların görebilmesi için dışa aktarır
  • " find *.txt -exec bash -c 'multiple_cmd "$0"' {} \;" - örneğinizde işlevi yürütecek bul

Bu şekilde multiple_cmd, ihtiyacınız olduğu kadar uzun ve karmaşık olabilir.

Bu yardımcı olur umarım.


mükemmel, tam ihtiyacım olan şey!
Anentropik

OSX'te benim için çalışmıyor
Thomas

@Tamamlar ama osx içinde test edilen bu tek astarı deneyin. Orada bazı dosyalar / dizinler ve ona CDd ile 'aaa' adlı bir dizin yaptım. Sonra, ~/aaa$ acmd() { echo x \"$1\" x; }; export -f acmd; find . -exec bash -c 'acmd {}' \;
barlop

@barlop, bunu bir deneyeceğim; Teşekkürler!
Thomas

14

Daha kolay bir yol var:

find ... | while read -r file; do
    echo "look at my $file, my $file is amazing";
done

Alternatif:

while read -r file; do
    echo "look at my $file, my $file is amazing";
done <<< "$(find ...)"

1
dosya adlarında yeni satırlar olabilir, bu yüzden find -print0 argümanına ve xargs -0 argümanına sahiptir
abasterfield

@abasterfield Ben her zaman vahşi lol olanlar bulmak umuyoruz
Camilo Martin

1
yapmak istediğim "find ... -exec zcat {} | wc -l \;" ki bu işe yaramadı. Ancak, bulmak ... | -r dosyasını okurken; echo "$ file: zcat $file | wc -l"; bitti, bu yüzden teşekkür ederim!
Greg Dougherty

Yukarıdaki yorumda "zcat $ file | wc -l" etrafında "geri keneler" var. Ne yazık ki SO bunları biçimlendirmeye dönüştürür, bu yüzden doğru kod görünür gerçek bir cevap olarak ekledim
Greg Dougherty

1
@GregDougherty Bunun `gibi ters eğik çizgiler kullandığınızı yapmak için ters tırnaklardan kaçabilirsiniz : \​`(yine de, bunun $()yerine kullanmak için başka bir iyi neden ).
Camilo Martin

8

Bunu find ile yapabilirsiniz eğer bilmiyorum, ama alternatif bir çözüm bir kabuk komut dosyası oluşturmak ve find ile çalıştırmak olacaktır.

lastline.sh:

echo $(tail -1 $1),$1

Komut dosyasını yürütülebilir yapın

chmod +x lastline.sh

Kullanım find:

find . -name "*.txt" -exec ./lastline.sh {} \;

7
backticks kullanımdan kaldırılmıştır, lütfen daha iyi okunabilir, yazı tipinden bağımsız ve yuvalaması kolay olan $ (...) kullanımını teşvik edin. Teşekkür ederim.
kullanıcı bilinmiyor

4

Denis'in ilk cevabı, sorunu çözmek için verilen cevaptır. Ama aslında sadece bir yürütme başlığı önermek gibi birkaç komutları ile bir bulmak değil. Bir exec'a birkaç komutla cevap vermek için, resolv için başka bir şey aramamız gerekecek. İşte bir örnek:

Birkaç {} referans kullanarak 1 exec komutu kullanılarak son 7 gün içinde değiştirilmiş son 10000 satır .log dosyası saklayın

1) komutun hangi dosyalar üzerinde ne yapacağına bakın:

find / -name "*.log" -a -type f -a -mtime -7 -exec sh -c "echo tail -10000 {} \> fictmp; echo cat fictmp \> {} " \;

2) Yapın: (daha fazla not \ "" değil, sadece ">" bu istenir)

find / -name "*.log" -a -type f -a -mtime -7 -exec sh -c "tail -10000 {} > fictmp; cat fictmp > {} ; rm fictmp" \;


Ancak dosya adlarından birinin bir alanı varsa, bu kırılacağını düşünüyorum.
Camilo Martin

4

Camilo Martin sayesinde ilgili bir soruya cevap verebildim:

Yapmak istediğim şey

find ... -exec zcat {} | wc -l \;

ki bu işe yaramadı. Ancak,

find ... | while read -r file; do echo "$file: `zcat $file | wc -l`"; done

işe yarıyor, bu yüzden teşekkür ederim!


2

@ Tinker'ın cevabını genişletmek,

Benim durumumda, hem dosya adını hem de bulunan metni belirli bir metni içeren dosyalarda yazdırmak için bir command | command | commandiç yapmak zorunda kaldım -exec.

Bunu yapabildim:

find . -name config -type f \( -exec  grep "bitbucket" {} \; -a -exec echo {} \;  \) 

sonuç:

    url = git@bitbucket.org:a/a.git
./a/.git/config
    url = git@bitbucket.org:b/b.git
./b/.git/config
    url = git@bitbucket.org:c/c.git
./c/.git/config

1
Ayrıca, komutla /dev/nullikinci bir argüman olarak greptek bir -execparametre ile dosya adını ve grep'd içeriğini tek bir satırda yazdırabilirsiniz :find . -name config -type f -exec grep "bitbucket" {} /dev/null \;
Bill Feth

1

xargs kullanmalı :)

find *.txt -type f -exec tail -1 {} \; | xargs -ICONSTANT echo $(pwd),CONSTANT

başka bir tane (osx üzerinde çalışıyor)

find *.txt -type f -exec echo ,$(PWD) {} + -exec tail -1 {} + | tr ' ' '/'

3
Bu find, eşleşen dosya sayısının bir komut satırı için çok büyük olduğu durumlar için önemli bir kullanım durumuna bakar . -execbu sınırı aşmanın bir yoludur. Bir yardımcı programa yöneltmek bu yararı özlüyor.
Chris Johnson

xargs -nçağrı başına eşleşme sayısını seçmek için vardır. her maç için xargs -n 1 foocmdyürütülür foocmd {}.
AndrewF

0

Bir find+xargscevap.

Aşağıdaki örnek tüm .htmldosyaları bulur ve .BAKuzantı eklenmiş bir kopyasını oluşturur (örn. 1.html> 1.html.BAK).

Birden çok yer tutuculu tek komut

find . -iname "*.html" -print0 | xargs -0 -I {} cp -- "{}" "{}.BAK"

Birden çok yer tutuculu çoklu komutlar

find . -iname "*.html" -print0 | xargs -0 -I {} echo "cp -- {} {}.BAK ; echo {} >> /tmp/log.txt" | sh

# if you need to do anything bash-specific then pipe to bash instead of sh

Bu komut ayrıca, bir tire ile başlayan veya -my file.htmlparametre alıntılama ve --sonrasında parametrelerin sonuna ve gerçek dosya adlarının başlangıcına cpsinyal gönderilmesi gibi boşluklar içeren dosyalarla da çalışır cp.

-print0 sonuçları boş bayt sonlandırıcılar ile bağlar.


için Xargs-I {} parametresi tanımlamaktadır {}tutucu olarak; istediğiniz yer tutucuyu kullanabilirsiniz; -0girdi öğelerinin boş ayrıldığını gösterir.

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.