Bir önceki komutun çıktısını argüman olarak bir sonrakine ilet


118

Stdout ( command1 -p=aaa -v=bbb -i=4) 'a veri veren bir komut kullandım . Çıkış çizgisi aşağıdaki değere sahip olabilir:

rate (10%) - name: value - 10Kbps

Bu oranı 'depolamak' için saklamak istiyorum (burada piponun faydalı olacağını tahmin ediyorum). Ve son olarak, bu oranın ikinci komuttaki bir parametrenin değeri olmasını isterim (diyelim command2 -t=${rate})

Benim tarafımda zor görünüyor; Borular, grep, sed ve benzerlerinin nasıl kullanılacağını daha iyi bilmek istiyorum.

Bunun gibi birçok kombinasyon denedim ama kafam karıştı:

$ command1 -p=aaa -v=bbb -i=4 | grep "rate" 2>&1 command2 -t="rate was "${rate}

Yanıtlar:


143

İki çok farklı türde girdiyi karıştırıyorsunuz.

  1. Standart giriş ( stdin)
  2. Komut satırı argümanları

Bunlar farklı ve farklı amaçlar için kullanışlıdır. Bazı komutlar her iki şekilde de girdi alabilir, ancak genellikle bunları farklı şekilde kullanırlar. Örneğin şu wckomutu al:

  1. Girerek giriş stdin:

    ls | wc -l
    

    Bu çıktıdaki satırları sayar ls

  2. Komut satırı argümanlarına göre girdi geçmek:

    wc -l $(ls)
    

    Bu, tarafından basılan dosyalar listesindeki satırları sayar .ls

Tamamen farklı şeyler.

Sorunuzu yanıtlamak için, ilk komutun çıktısından oranı yakalamak ve ardından ikinci komut için bir komut satırı argümanı olarak kullanmak istediğiniz gibi görünüyor. İşte bunu yapmanın bir yolu:

rate=$(command1 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p')
command2 -t "rate was $rate"

Açıklaması sed:

  • s/pattern/replacement/Komut bazı desen değiştirmektir
  • Desen anlamına gelmektedir: hattı "oranı" ile başlamalıdır ( ^rate) herhangi iki karakteri (ardından ..bir ardından 0 veya daha fazla rakam elde edilmiş), %metnin geri kalan kısmında, ardından ( .*)
  • \1değişimde, içinde yakalanan ilk ifadenin içeriği anlamına gelir; \(...\)bu durumda, %işaretten önceki rakamlar
  • -nBayrağı sedkomutu varsayılan olarak satırları yazdırmak değil demektir. pSonunda s///komuta yerine varsa çizgiyi basmak demektir. Kısacası, komut yalnızca bir eşleşme olduğunda bir şey yazdıracaktır.

13

Bunu kullanma eğilimindeyim:

command1 | xargs -I{} command2 {}

command1Yerine (parantez) kullanarak xargs çıkışını geçirin command2. Command1 ise findkullandığınızdan emin olun -print0ve eklemek -0için xargsboş dizeleri sonlandırıldı ve xargsarayacak command2bulunan her şey için.

Senin durumunda (ve @Janos’tan sed çizgisini alarak):

command1 -p=aaa -v=bbb -i=4 | sed -ne 's/^rate..\([0-9]*\)%.*/\1/p' | xargs -I{} command2 -t="rate was {}"

Bu her şeyi güzel tutar ve pipolanır, bu yüzden bundan hoşlanırım.
Mateen Ulhaq

4

Çıktısını simüle etmek için command1bu yankı ifadesini kullanıyorum:

$ echo -e "Foo\nrate (10%) - name: value - 10Kbps\nBar"
$ alias command1='echo -e "Blah\nrate (10%) - name: value - 10Kbps\nBlag"'

Hızlı bir test:

$ command1
Blah
rate (10%) - name: value - 10Kbps
Blag

Hepsi iyi, öyleyse ayrıştıralım:

$ command1 | grep 'rate'
rate (10%) - name: value - 10Kbps

Böylece istediğimiz çizgiyi elde ederiz command1, şunu geçelim command2:

$ alias command2='echo'
$ command2 -t="rate was "$(command1 | grep 'rate')
-t=rate was rate (10%) - name: value - 10Kbps

"rate was "$(command1 | grep 'rate')Otomatik olarak birleştirmeyi bekliyorum . Bu, boşluk nedeniyle çalışmazsa, bunun yerine girişi geçebilmeniz gerekir:

$ alias command2='echo'
$ command2 -t=$(echo '"rate was ' $(command1 | grep 'rate') '"')
-t="rate was rate (10%) - name: value - 10Kbps "


2

İlk görev, oranı o satırdan çıkarmak. GNU grep (gömülü olmayan Linux veya Cygwin) ile -oseçeneği kullanabilirsiniz . İstediğiniz kısım yalnızca rakam içeren ve ardından bir %işarettir. %Kendisini çıkarmak istemiyorsan , ek bir numaraya ihtiyacın var: sıfır genişlikte bir bakış açısı iddiası , ancak hiçbir şey takip etmiyor, ancak hiçbir şey takip etmiyorsa %.

command1 -p=aaa -v=bbb -i=4 | grep -o -P '[0-9]+(?=%)'

Başka bir olasılık sed kullanmaktır. Bir çizginin bir kısmını sed'de çıkarmak için, skomutu tüm çizgiyle eşleşen bir regex ile (ile başlayan ^ve biten $), bir grupta tutulacak kısımla ( \(…\)) kullanın. Tüm çizgiyi, tutulacak grupların içeriğiyle değiştirin. Genel olarak, -nvarsayılan yazdırmayı kapatma ve pdeğiştiriciyi çıkarılacak bir şeyin olduğu satırlara yazdırma seçeneğine geçin (burada tek bir satır olması önemli değil). Bkz eşleşen bir desen sonra hattın sadece bir bölümünü iade ve çevredeki karakterleri yazdırmadan 'sed' ile eşleşen bir düzenli ifade ayıklanıyor daha sed hileler için.

command1 -p=aaa -v=bbb -i=4 | sed 's/^.*rate(\([0-9]*\)%).*$/\1/'

Yine sedden daha esnek, garip. Awk, her satır için talimatları küçük bir zorunlu dilde yürütür. Oranı buraya çekmenin birçok yolu var; İkinci alanları seçiyorum (alanlar varsayılan olarak boşluklarla sınırlandırılmış) ve içindeki rakam olmayan tüm karakterleri kaldırıyorum.

command1 -p=aaa -v=bbb -i=4 | awk '{gsub(/[^0-9]+/, "", $2); print $2}'

Şimdi oranı çıkardığın bir sonraki adım, bunu argüman olarak atmak command2. Bunun için bir araç bir emirdir . İçine bir komut koyarsanız $(…)(dolar-parantez), çıktısı komut satırına yerleştirilir. Komutun çıktısı, her boşluk bloğunda ayrı sözcüklere bölünür ve her sözcük bir joker desen olarak değerlendirilir; Böyle olup istemedikçe, komut ikamesi sonuna çift tırnak koyun: "$(…)". Çift tırnak ile, komutun çıktısı doğrudan tek bir parametre olarak kullanılır (tek dönüşüm, çıktının sonundaki yeni satırların kaldırılmasıdır).

command2 -t "$(command1 -p=aaa -v=bbb -i=4 |
               sed 's/^.*rate(\([0-9]*\)%).*$/\1/')"

0

Kullanabilirsiniz grepve PCRE - Perl Uyumlu Normal İfadeler. Bu, oranın değeriyle eşleşmesi için, "oran" dizesinin dahil edilmesine gerek kalmadan, oranınıza uyması için bir göz atma kullanmanıza olanak tanır.

Örnek

$ echo "rate (10%) - name: value - 10Kbps" | grep -oP '(?<=^rate \()\d+'
10

ayrıntılar

Yukarıdaki şekilde grepçalışır:

  • -osadece aradığımız şeyi geri getireceğiz \d+, ki bu parenler içindeki rakamlardır.
  • -P grep PCRE özelliğini etkinleştirir
  • (?<=^rate \() yalnızca "rate (" ile başlayan dizeleri döndürür

command2

"Rate" in değerini yakalamak için şöyle koşabilirsiniz command1:

$ rate=$(command 1 | grep -oP '(?<=^rate \()\d+'

Sonra 2. komutunuz için bu değişkeni kullanmanız yeterlidir.

$ command2 -t=${rate}

Süslü olabilir ve hepsini tek bir çizgi yapabilirsin:

$ command2 -t=$(command1 | grep -oP '(?<=^rate \()\d+')

Bu, komut $(..)bloğundaki komut1'i yürütür , sonuçlarını alır ve komut2'nin -t=..anahtarına dahil eder .


0

Genelde çıktıyı başka bir komuta argüman olarak yerleştirmek için `command` komutunu kullanırım. Örneğin, freebsd'de işlem foo tarafından tüketilen kaynağı bulmak için:

procstat -r `pgrep -x foo`

Burada, pgrep, işlem PID'sini argüman olarak bekleyen procstat komutuna iletilen işlem foo'sunun PID'sini çıkarmak için kullanılır.

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.