Bazı komutlar neden standart girdilerinden okunmuyor?


19

Ne zaman boru hattı kullanmamız ve ne zaman kullanmamamız gerektiğini merak ediyorum.

Örneğin, pdf dosyalarını işleyen belirli bir işlemi öldürmek için, aşağıdakileri ardışık düzen kullanarak çalışmaz:

ps aux | grep pdf | awk '{print $2}'|kill

Bunun yerine, yalnızca aşağıdaki yollarla yapabiliriz:

kill $(ps aux| grep pdf| awk '{print $2}')

veya

ps aux | grep pdf | awk '{print $2}'| xargs kill

Göre man bash(sürümü 4.1.2):

The standard output of command is connected via a pipe to the standard input of command2.

Yukarıdaki senaryo için:

  • stdin grep, stdout olduğunu ps. Bu çalışır.
  • stdin awk, stdout olduğunu grep. Bu çalışır.
  • stdin kill, stdout olduğunu awk. Bu işe yaramıyor.

Aşağıdaki komutun stdin'i her zaman önceki komutun stdout'undan girdi almaktadır.

  • Neden killveya ile çalışmıyor rm?
  • Arasında farklı nedir kill, rmile giriş grep, awkgiriş?
  • Herhangi bir kural var mı?

1
Bu bir cevap değil pgrep, pkillve killallkomutlarına bir göz atmak isteyebilirsiniz .
terdon

2
@terdon: Sadece boru hattı sorununu göstermek için yukarıdaki senaryoyu kullanıyorum, anlıyorum pgrepve geri kalanı bunu mükemmel bir şekilde başarabilir :)
sylye

Yanıtlar:


17

Programlara girdi sağlamanın iki yaygın yolu vardır:

  • süreçlerin STDIN'ına veri sağlama
  • komut satırı bağımsız değişkenlerini belirtin

killyalnızca komut satırı bağımsız değişkenlerini kullanır. STDIN'den okumuyor. STDIN gibi grepve awkokuyan programlar (komut satırı bağımsız değişkenleri olarak dosya adı verilmezse) ve verileri komut satırı bağımsız değişkenlerine (desen, deyimler, bayraklar, ...) göre işler.

Komut satırı bağımsız değişkenlerine değil, yalnızca diğer işlemlerin STDIN'ine geçebilirsiniz.

Ortak kural, programların rastgele miktarda veri işlemek için STDIN kullanmasıdır. Tüm ekstra giriş parametreleri veya genellikle çok azı varsa, komut satırı bağımsız değişkenleri tarafından iletilir. Komut satırı çok uzun sürebilir, örneğin uzun awkprogram metinleri için, bunları genellikle ekstra program dosyalarından okuma -fseçeneği vardır ( seçeneği awk).

Programların STDOUT'unu komut satırı bağımsız değişkenleri olarak kullanmak için $(...)veya çok fazla veri olması durumunda kullanın xargs. findbunu da doğrudan yapabilirsiniz -exec ... {} +.

Tamlık için: STDOUT'a komut satırı bağımsız değişkenleri yazmak için kullanın echo.


1
Bir komutun yalnızca bağımsız değişkenler alacağını, ancak STDIN'i almayacağını nasıl bilebiliriz ? Kılavuzdan tahmin etmek veya okumak yerine sistematik veya programatik bir yol var mı? Sadece man sayfasını okuyarak, komutun STDIN alıp alamayacağına dair kesin bir ipucu alamadım, çünkü STDIN bir man sayfasının mevcut şeklindeki argümanların bir parçası. Örneğin gzip, SYNOPSIS'te girdi olarak bir FILENAME alması gerektiğini söylemedi. Bunu belirlemenin daha sistematik bir yolu olduğunu düşünüyorum.
sylye

Bazı komutlar için "stdin" (veya "stdout") anlamına gelen "-" argümanı da vardır.
Emmanuel

Olmaz xargsdoğrusu "komut satırı argümanları boru" için izin?
T. Verron

@ T.Verron evet, görevi bu xargs. Gerekirse komutu bir kereden fazla çağırır (komut satırı boyutu sınırlıdır) ve başka birçok seçeneği vardır.
jofel

2
Açıklamanın metni programı nasıl kullanabileceğinizi açıklayacaktır. Örneğin, gzip diyor ki: "gzip programı, dosyaları Lempel-Ziv kodlaması (LZ77) kullanarak sıkıştırır ve açar. Hiçbir dosya belirtilmezse, gzip standart girdiden sıkıştırır veya standart çıktıya açar." Bir kılavuz sayfası standart girdiden bahsetmezse, bunu kullanmaz.
Alan Shutko

16

Bu ilginç bir soru ve Unix / Linux felsefesinin bir kısmını ele alıyor.

Yani, gibi programlar arasındaki fark nedir grep, sed, sortve bir yandan kill, rm, lsdiğer taraftan? İki yönü görüyorum.

filtre boy

  • İlk tür programlara filtre denir . Bir dosyadan veya STDIN'den bir girdi alırlar, değiştirirler ve çoğunlukla STDOUT için bir çıktı oluştururlar. Kaynaklar ve hedefler olarak diğer programlarla birlikte bir boruda kullanılması amaçlanmıştır.

  • İkinci tür programlar bir girdiye etki eder, ancak verdikleri çıktı genellikle girdiyle ilgili değildir. killdüzenli çalıştığında hiçbir çıktısı yoktur, ne de çalışır ls. Sadece başarı göstermek için bir dönüş değeri var. Normalde STDIN'den girdi almazlar, ancak çoğunlukla STDOUT'a çıktı verirler.

Gibi programlar için ls, filtre yönü o kadar iyi çalışmıyor. Kesinlikle bir girdisi olabilir (ancak bir tane gerekmez) ve çıktı bu girdiyle yakından ilişkilidir, ancak bir filtre olarak çalışmaz. Ancak, bu tür programlar için diğer yön hala işe yarıyor:

semantik yönü

  • Filtreler için girdilerinin anlamsal bir anlamı yoktur . Sadece verileri okurlar, verileri değiştirirler, verileri çıkarırlar. Bunun sayısal değerler, bazı dosya adları veya HTML kaynak kodu listesi olması önemli değildir. Bu verilerin anlamı sadece kod tarafından verilir Eğer için regex: filtreye sağlamak grepiçin kurallar awkveya Perl programı.

  • killVeya gibi diğer programlar lsiçin girdilerinin bir anlamı , bir ifadesi vardır . killişlem numaralarını, lsdosya veya yol adlarını bekler. Rasgele verileri işleyemezler ve amaçlanmazlar. Birçoğu gibi herhangi bir girdi veya parametreye bile ihtiyaç duymaz ps. Normalde STDIN'den okumazlar.

Muhtemelen bu iki yönü birleştirmek mümkündür: Filtre, girdisi program için anlamsal bir anlamı olmayan bir programdır.

Eminim bu felsefe hakkında bir yerde okudum, ama şu anda hiçbir kaynağı hatırlamıyorum, üzgünüm. Birinde bazı kaynaklar varsa, lütfen düzenlemekten çekinmeyin.


5

Böyle bir "kural" yoktur. Bazı programlar STDIN'den girdi alır, bazıları almaz. Bir program STDIN'den girdi alabilirse, yapılamaz.

Normalde bir programın ne yapılacağını düşünerek girdi alıp almayacağını anlayabilirsiniz. Programın işi bir şekilde bir dosyanın içeriğini (ör grep. sed, awkVb.) Değiştirmekse, normalde STDIN'den girdi alır. Onun iş dosyasını kendisi (örn işlemek için ise mv, rm, cp) ya da bir işlem (örneğin kill, lsof) ya da bir şey hakkında geri dönüş bilgilere (örneğin top, find, ps) daha sonra öyle değil.

Bunu düşünmenin bir başka yolu da argümanlar ve girdi arasındaki farktır. Örneğin:

mv foo bar

Yukarıdaki komutta mvböyle bir girdi yok. Verilen iki argüman. Her iki dosyada da ne olduğunu bilmiyor ya da umursamıyor, sadece bunların argümanları olduğunu biliyor ve onları manipüle etmeli.

Diğer yandan

sed -e 's/foo/bar/' < file
--- -- ------------   ----
 |   |       |          |-> input
 |   |       |------------> argument        
 |   |--------------------> option/flag/switch
 |------------------------> command

Burada sedbir argümanın yanı sıra girdi verilmiştir. Girdi aldığı için STDIN'den okuyabilir ve pipetlenebilir.

Bir argüman olabilir zaman daha karmaşık bir hal alıyor olması girişi. Örneğin

cat file

Burada fileverilen argüman cat. Kesin olmak gerekirse, dosya adı file bağımsız değişkendir. Bununla birlikte, catdosyaların içeriğini işleyen bir program olduğundan, girdisi içindeki her şeydir file.

Bu, straceişlemler tarafından yapılan sistem çağrılarını izleyen bir program kullanılarak gösterilebilir . Biz çalıştırırsanız cat fooaracılığıyla strace, biz dosya olduğunu görebilirsiniz fooaçılır:

$ strace cat foo 2| grep foo
execve("/bin/cat", ["cat", "foo"], [/* 44 vars */]) = 0
open("foo", O_RDONLY)     

Gösterir yukarıdaki ilk satır programı bu /bin/catdenilen ve bağımsız değişkenleri idi catve foo(ilk değişken programın kendisi her zaman). Daha sonra, argüman foosalt okunur modda açıldı. Şimdi bunu karşılaştırın

$ strace ls foo 2| grep foo 
execve("/bin/ls", ["ls", "foo"], [/* 44 vars */]) = 0
stat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat("foo", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
write(1, "foo\n", 4foo

Burada da lskendini ve fooargüman olarak aldı . Ancak, opençağrı yoktur , argüman girdi olarak değerlendirilmez. Bunun yerine, dosya hakkında bilgi almak lsiçin sistemin statkitaplığını ( statkomutla aynı şey değildir) çağırır foo.

Özetle, çalıştırdığınız komut girdisini okuyacaksa, buna yönlendirebilirsiniz, eğer yapmazsa yapamazsınız.


0
  • Neden kill veya rm ile çalışmıyor?

kill ve rm STDIN gerekmez.

  • Kill, grep ile rm girişi, awk girişi arasındaki fark nedir?

İçin killve rmkullanıcıların argüman olarak onların özelleştirilmiş bilgi vermek ve$(cmd) bir STDOUT alarak yardımcı olur cmdve ona bilgi argüman dönüştürme.

İçin grepve awkkullanıcıların argümanlar ve ek olarak, aynı zamanda sağlamak STDINveya komutla tarafından işlenecektir düzenli dosya. STDINboru hattı ile geçirilebilir| veya elle girilerek .

  • Herhangi bir kural var mı?

Kılavuzu veya kaynak kodlarını okuyun. Ve ihtiyacınız olan hiçbir şey bulamazsanız, basit ama tehlikeli bir test yapabilirsiniz:

Merak ettiğiniz komutu, daha önce anladığınız argümanlarla girin ve komutun duraklayıp duraklamadığına bakın (hiçbir şey olmuyor). O duraklarsanız, aslında (deneyebileceğiniz STDIN'den bekliyor catve echodiğerlerinden farkı görmek için). Manuel olarak yazarsınız Ctrl-Dve komut devam eder (sonuçları veya hataları göster) ve geri döner. Böyle bir komutun bu durumda STDIN'ye (sağladığınız argümanlarla) ihtiyacı vardır.

Aynı komutun farklı durumlarda STDIN'e ihtiyacı olmayabilir (örn cat. STDIN'yi bekler, ancak beklemez cat file.txt).

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.