2013-09-24 15 views
5

Dato un file "foo.txt", creato da:subshell IO reindirizzamento

$ seq 1 10 > "foo.txt" 

Sto cercando di leggere sia la prima e l'ultima riga del file, e ho iniziato reindirizzando il file in una subshell, in modo che l'elenco dei comandi consumerà il file in sequenza - ogni comando consuma l'input dal punto l'ultimo comando ha lasciato, suppongo:

$ (head -1; tail -1) < "foo.txt" 
1 
10 

Tuttavia, se provo lo stesso con un temporanea descrittore di file, l'uscita non è la stessa:

$ (head -1; tail -1) < <(seq 1 10) 
1 

Domande:

  1. Non sono sicuro di quello di nominare <(seq 1 10), ma qual è la differenza tra questo temporanea descrittore di file e regolare uno ("foo.txt"), che fa sì che l'esecuzione di subshell si comporti in modo diverso?

  2. Come posso ottenere lo stesso comportamento di reindirizzare un "foo.txt" alla subshell, ma senza un file temporanei - senza in realtà la creazione di un file.

risposta

5

È solo un problema di buffering. Prova:

cat foo.txt | (head -1; tail -1) 

e tu (probabilmente) vedrai la stessa cosa (la testa consuma l'intero input). Probabilmente ciò che sta accadendo è che la testa si comporta diversamente con un file normale che con una pipe, e la sostituzione del processo (che è il nome per la sintassi <(cmd)) sta creando una pipe. (In Linux, il head da coreutils Gnu fa un lseek per cercare di riposizionare nella nuova riga finale che emette, ma il lseek fallisce su un tubo.)

Prova:

(head -1; tail -1) < <(cat /usr/share/dict/words) 

Qui, head consuma solo la prima pagina di input e tail vede la riga finale dei dati.

Il comportamento che si sta vedendo non è ben definito, poiché non esiste uno standard che stabilisca la quantità di dati che è possibile consumare. Se si sostituisce head con sh -c 'read line; echo "$line"', si otterrà il comportamento desiderato in tutti i casi. (Oppure scrivi il tuo strumento per fornire il comportamento di head che desideri - stampando un numero fisso di linee pur non consumando più di quello.)

+1

+1 per una spiegazione molto buona. Tuttavia, l'OP chiede se è possibile ottenere tale comportamento senza alcun file temporaneo. È? I miei test non hanno avuto successo. – fedorqui

+0

Sostituendo 'head' con riga di lettura' sh -c ", echo" $ line "'', il comportamento desiderato può essere realizzato senza un file temporaneo –

+0

+1 Questa è la spiegazione esatta che stavo cercando!Visto che hai parlato di creare le tue cose, ho pensato di scrivere una mia shell con un paio di amici; stiamo pensando a una shell in qualche modo funzionale, con pattern matching e tutti i trickster più fantastici (: – Rubens