Komut çıkışının her satırına shell komutu nasıl uygulanır?


192

Bir komuttan (örneğin ls -1) bazı çıktılar aldığımı varsayalım :

a
b
c
d
e
...

echoSırayla her birine bir komut uygulamak istiyorum . Örneğin

echo a
echo b
echo c
echo d
echo e
...

Bunu bash'da yapmanın en kolay yolu nedir?


3
ls -1burada bir örnek olabilir, ancak çıktısını ayrıştırmanın iyi olmadığını hatırlamak önemlidir ls. Bkz: mywiki.wooledge.org/ParsingLs
codeforester

Yanıtlar:


217

Muhtemelen kullanımı en kolay olanıdır xargs. Senin durumunda:

ls -1 | xargs -L1 echo

-LBayrak girişi düzgün okunur sağlar. Man sayfasından xargs:

-L number
    Call utility for every number non-empty lines read. 
    A line ending with a space continues to the next non-empty line. [...]

24
lsotomatik olarak -1bir boruda yapar.
sonraki duyuruya kadar duraklatıldı.

5
@Dennis, öyle görünmüyor: ls | xargs -L2 echove ls -1 | xargs -L2 echoiki farklı çıktı veriyor. İlki tek bir hatta.
Alex Budovski

2
@Alex: Aynı çıktıyı alıyorum.
sonraki duyuruya kadar duraklatıldı.

6
xargskabuk işlevlerini veya kabuk yerleşik komutlarını değil, yalnızca yürütülebilir dosyaları çalıştırabilir. Birincisi için en iyi çözüm muhtemelen readbir döngüde olan çözümdür .
pabouk

12
Keşke bu cevabın ne -L1için bir açıklama içermesini isterdim .
Wyck

164

Her satırda temel bir başa ekleme işlemi kullanabilirsiniz:

ls -1 | while read line ; do echo $line ; done

Veya daha karmaşık işlemler için çıkışı boru hattına bağlayabilirsiniz:

ls -1 | sed 's/^\(.*\)$/echo \1/'

1
Sed komutu işe yaramadı: sh: cho: not found a sh: cho: not foundGörünüşe egöre bir sed komutu falan için yankı alıyor .
Alex Budovski

whileDöngü için +1 . cmd1 | while read line; do cmd2 $line; done. Ya while read line; do cmd2 $line; done < <(cmd1)da alt kabuk oluşturmayan. Bu, sedkomutunuzun basitleştirilmiş sürümüdür :sed 's/.*/echo &/'
sonraki duyuruya kadar duraklatıldı.

1
@Alex: çift tırnak işaretlerini tek tırnak olarak değiştirin.
sonraki duyuruya kadar duraklatıldı.

5
"$line"Sözcük bölünmesini önlemek için while döngüsünde alıntı yapın .
ignis

3
Kaçan karakterlerle karıştırmayı read -r lineönlemek için kullanmayı deneyin read. Örneğin , kaçışını kaybetmiş echo '"a \"nested\" quote"' | while read line; do echo "$line"; doneverir "a "nested" quote". Eğer yaparsak beklediğimiz gibi echo '"a \"nested\" quote"' | while read -r line; do echo "$line"; donealırız "a \"nested\" quote". Bkz. Wiki.bash-hackers.org/commands/builtin/read
Warbo

9

For döngüsü kullanabilirsiniz :

* içindeki dosya için; yapmak
   echo "$ file"
tamam

Söz konusu komut birden fazla bağımsız değişkeni kabul ederse, xargs kullanmanın , söz konusu yardımcı programı birden çok kez yerine yalnızca bir kez oluşturması gerektiğinden neredeyse her zaman daha verimli olduğunu unutmayın.


1
Xargs'ın doğru / güvenli kullanımını açıklamaya değer, yani. printf '%s\0' * | xargs -0 ...- Aksi takdirde, boşluk, tırnak işareti vb. içeren dosya adlarıyla oldukça güvensizdir
Charles Duffy

8

Aslında olabilir , bunu yapmak için sed GNU sed koşuluyla kullanın.

... | sed 's/match/command \0/e'

Nasıl çalışır:

  1. Komut eşleşmesi ile ikame eşleşmesi
  2. İkamede çalıştır komutu
  3. Değiştirilen satırı komut çıkışıyla değiştirin.

Fantastik. Sonunda e komutunu koymayı unuttum , ancak cevabınızı gördükten sonra yaptım ve işe yaradı. SED bir çizgiyle eşleştiğinde 1000 ile 15000 arasında rastgele bir kimlik eklemeye çalışıyordum. cat /logs/lfa/Modified.trace.log.20150904.pw | sed -r 's/^(.*)(\|006\|00032\|)(.*)$/echo "\1\2\3 - ID `shuf -i 999-14999 -n 1`"/e'
sgsi


2

xargs ters eğik çizgi, tırnak işareti ile başarısız olur. Bunun gibi bir şey olmalı

ls -1 |tr \\n \\0 |xargs -0 -iTHIS echo "THIS is a file."

xargs -0 seçeneği:

-0, --null
          Input  items are terminated by a null character instead of by whitespace, and the quotes and backslash are
          not special (every character is taken literally).  Disables the end of file string, which is treated  like
          any  other argument.  Useful when input items might contain white space, quote marks, or backslashes.  The
          GNU find -print0 option produces input suitable for this mode.

ls -1yeni satır karakterleri olan öğeleri sonlandırır, bu nedenle tronları boş karakterlere dönüştürür.

Bu yaklaşım, manuel olarak yinelemekten yaklaşık 50 kat daha yavaştır for ...(bkz. Michael Aaron Safyan'ın cevabı) (3.55s ve 0.066s). Ancak locate, find, bir dosyadan ( tr \\n \\0 <file) veya benzeri bir şeyden okuma gibi diğer giriş komutları için bununla çalışmanız gerekir xargs.


1

Benim için daha iyi sonuç:

ls -1 | xargs -L1 -d "\n" CMD

Daha iyi, ama mükemmel değil. find . -mindepth 1 -maxdepth 1 -print0 | xargs -0 commandçıktısının ls -1belirsiz olduğu durumları ele alacaktır ; her biri için bir lider istemiyorsanız -printf '%P\0'yerine kullanın . -print0./
Charles Duffy

1

örneğin, bir listede birden çok komut çalıştırmak için gawk kullanmayı seviyorum

ls -l | gawk '{system("/path/to/cmd.sh "$1)}'

ancak kaçan karakterlerin kaçması biraz kıllı olabilir.

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.