Perché alcuni comandi non leggono dal loro input standard?


19

Mi chiedo cosa quando dovremmo usare la pipeline e quando non dovremmo.

Ad esempio, per interrompere un determinato processo che gestisce i file pdf, non funzionerà utilizzando la pipeline:

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

Invece, possiamo farlo solo con i seguenti modi:

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

o

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

Secondo man bash(versione 4.1.2):

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

Per lo scenario sopra:

  • lo stdin di grepè lo stdout di ps. Che funzioni.
  • lo stdin di awkè lo stdout di grep. Che funzioni.
  • lo stdin di killè lo stdout di awk. Non funziona

Lo stdin del seguente comando riceve sempre input dallo stdout del comando precedente.

  • Perché non funziona con killo rm?
  • Qual è la differenza tra kill, rminput with grep, awkinput?
  • Ci sono delle regole?

1
Questa non è una risposta, ma si potrebbe desiderare di avere uno sguardo ai pgrep, pkille killallcomandi.
terdon

2
@terdon: ho appena usato lo scenario sopra per mostrare il problema della pipeline, lo capisco pgrepe il resto lo può raggiungere perfettamente :)
sylye,

Risposte:


17

Esistono due modi comuni per fornire input ai programmi:

  • fornire dati a STDIN dei processi
  • specifica gli argomenti della riga di comando

killutilizza solo argomenti della riga di comando. Non legge da STDIN. Programmi come grepe awkletti da STDIN (se non vengono forniti nomi di file come argomenti della riga di comando) ed elaborano i dati secondo i loro argomenti della riga di comando (modello, istruzioni, flag, ...).

È possibile eseguire il pipe su STDIN di altri processi, non su argomenti della riga di comando.

La regola comune è che i programmi usano STDIN per elaborare quantità arbitrarie di dati. Tutti i parametri di input extra o, se ce ne sono solo pochi, vengono passati dagli argomenti della riga di comando. Se la riga di comando può diventare molto lunga, ad esempio per awktesti di programma lunghi , spesso c'è la possibilità di leggerli da file di programma extra ( -fopzione di awk).

Per utilizzare STDOUT dei programmi come argomenti della riga di comando, utilizzare $(...)o in caso di molti dati xargs. findpuò anche questo direttamente con -exec ... {} +.

Per completezza: per scrivere argomenti della riga di comando su STDOUT, utilizzare echo.


1
Come sappiamo che un comando accetta solo argomenti ma non STDIN? Esiste un modo sistematico o programmatico piuttosto che indovinare o leggere dalla pagina man? Leggendo solo la pagina man, non sono riuscito a ottenere indizi specifici per stabilire se il comando può o non può accettare STDIN, poiché anche STDIN fa parte degli argomenti dal modo in cui una pagina man presenta. Ad esempio, gzipnella SINOSSI, non ha detto che deve prendere un FILENAME come input. Sto cercando c'è un modo più sistematico per determinarlo.
sylye,

C'è anche l'argomento "-" che significa "stdin" (o "stdout") per alcuni comandi.
Emmanuel,

Non ti xargsconsentirà di "reindirizzare gli argomenti della riga di comando"?
T. Verron,

@ T.Verron sì, questo è il compito di xargs. Chiama il comando se necessario più di una volta (la dimensione della riga di comando è limitata) e ha molte altre opzioni.
jofel,

2
Il testo della descrizione descriverà come è possibile utilizzare il programma. Ad esempio, gzip dice: "Il programma gzip comprime e decomprime i file utilizzando la codifica Lempel-Ziv (LZ77). Se non viene specificato alcun file, gzip comprime dall'input standard o si decomprime in output standard." Se una pagina man non menziona l'input standard, non lo utilizzerà.
Alan Shutko,

16

Questa è una domanda interessante e si occupa di una parte della filosofia Unix / Linux.

Quindi, qual è la differenza tra programmi come grep, sed, sortda un lato e kill, rm, lsd'altra parte? Vedo due aspetti.

L' aspetto del filtro

  • Il primo tipo di programmi è anche chiamato filtri . Prendono un input, da un file o da STDIN, lo modificano e generano un output, principalmente su STDOUT. Sono pensati per essere utilizzati in una pipe con altri programmi come fonti e destinazioni.

  • Il secondo tipo di programmi agisce su un input, ma l'output che danno spesso non è correlato all'input. killnon ha output quando funziona regolarmente, né lo fa ls. Hanno solo un valore di ritorno per mostrare il successo. Normalmente non accettano input da STDIN, ma forniscono principalmente output a STDOUT.

Per programmi come ls, l'aspetto del filtro non funziona così bene. Può certamente avere un input (ma non ne ha bisogno) e l'output è strettamente correlato a quell'input, ma non funziona come filtro. Tuttavia, per quel tipo di programmi, l'altro aspetto funziona ancora:

L' aspetto semantico

  • Per i filtri, il loro input non ha significato semantico . Semplicemente leggono i dati, modificano i dati, producono dati. Non importa se si tratta di un elenco di valori numerici, alcuni nomi di file o codice sorgente HTML. Il significato di questi dati è dato solo dal codice si forniscono al filtro: la regex per grep, le regole per awko il programma Perl.

  • Per altri programmi, come killo ls, il loro input ha un significato , una denotazione . killsi aspetta numeri di processo, si lsaspetta nomi di file o percorsi. Non possono gestire dati arbitrari e non sono destinati a farlo. Molti di loro non hanno nemmeno bisogno di input o parametri, come ps. Normalmente non leggono da STDIN.

Probabilmente si potrebbero combinare questi due aspetti: un filtro è un programma il cui input non ha un significato semantico per il programma.

Sono sicuro di aver letto di questa filosofia da qualche parte, ma al momento non ricordo fonti, mi dispiace. Se qualcuno ha alcune fonti presenti, non esitare a modificare.


5

Non ci sono "regole" in quanto tali. Alcuni programmi ricevono input da STDIN, altri no. Se un programma può ricevere input da STDIN, può essere reindirizzato, in caso contrario, non può.

Normalmente puoi dire se un programma prenderà input o meno pensando a cosa fa. Se il lavoro del programma è in qualche modo manipolare il contenuto di un file (ad es grep. sed, awkEcc.), Normalmente riceve input da STDIN. Se il suo compito è manipolare il file stesso (ad es mv. rm, cp) O un processo (ad es kill. lsof) O restituire informazioni su qualcosa (ad es top. find, ps) , Non funziona.

Un altro modo di pensarci è la differenza tra argomenti e input. Per esempio:

mv foo bar

Nel comando sopra, mvnon ha input in quanto tale. Ciò che è stato dato sono due argomenti. Non sa né si preoccupa di cosa c'è in nessuno dei file, sa solo che questi sono i suoi argomenti e dovrebbe manipolarli.

D'altro canto

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

Qui, sedè stato dato input e un argomento. Poiché accetta input, può leggerlo da STDIN e può essere reindirizzato.

Diventa più complicato quando un argomento può essere l'input. Per esempio

cat file

Ecco, filel'argomento che è stato dato cat. Per essere precisi, il nome del file fileè l'argomento. Tuttavia, poiché catè un programma che manipola il contenuto dei file, il suo input è quello che c'è dentro file.

Questo può essere illustrato usando straceun programma che tiene traccia delle chiamate di sistema effettuate dai processi. Se corriamo cat foovia strace, possiamo vedere che il file fooè aperto:

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

La prima riga sopra mostra che il programma è /bin/catstato chiamato e i suoi argomenti erano cate foo(il primo argomento è sempre il programma stesso). Successivamente, l'argomento è foostato aperto in modalità di sola lettura. Ora, confronta questo con

$ 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

Anche qui, ha lspreso se stesso e foocome argomenti. Tuttavia, non vi è alcuna openchiamata, l'argomento non viene trattato come input. Al contrario, lsle chiamate del sistema statbiblioteca (che non è la stessa cosa del statcomando) per ottenere informazioni sul file foo.

In breve, se il comando che stai eseguendo leggerà il suo input, puoi inoltrarlo, in caso contrario, non puoi.


0
  • Perché non funziona con kill o rm?

kille rmnon è necessario STDIN.

  • Qual è la differenza tra kill, rm input con grep, awk input?

Per kille rm, gli utenti forniscono le loro informazioni personalizzate come argomento e $(cmd)aiutano a prendere lo STDOUT cmde a convertirlo come argomento informativo .

Per grepe awk, gli utenti forniscono argomenti e, inoltre, anche STDINo un file normale che verrà elaborato dal comando. STDINpuò essere passato con pipeline |o inserendo manualmente.

  • Ci sono delle regole?

Leggi il manuale o i codici sorgente. E se non trovi nulla di cui hai bisogno, puoi fare un test semplice ma forse pericoloso:

Basta inserire il comando di cui sei curioso, con argomenti che hai già capito, e vedere se il comando si interrompe (non succede nulla). Se si interrompe, sta effettivamente aspettando STDIN (puoi provare cate echovedere le diverse). Digiti manualmente Ctrl-De il comando procede (mostra risultati o errori) e ritorna. Tale comando richiede STDIN in quella situazione (con argomenti forniti).

Lo stesso comando potrebbe non aver bisogno di STDIN in diverse situazioni (ad esempio, cataspetta STDIN ma cat file.txtnon).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.