2010-03-14 30 views
17

Quando il ciclo ricorsivo tra le cartelle con i file che contengono spazi lo script di shell che uso è di questa forma, copiati dalla internet:Cosa significa "<<(cmd args)" nella shell?

while IFS= read -r -d $'\0' file; do 
     dosomethingwith "$file"  # do something with each file 
    done < <(find /bar -name *foo* -print0) 

credo di aver capito il bit IFS, ma non capisco quello che il ' < <(...) 'caratteri significati. Ovviamente c'è una specie di piping in corso qui.

Google è molto difficile "< <", vedete.

+0

Non intendi "<<"? – reinierpost

+0

"man sh" è tuo amico, in ogni caso. – reinierpost

+4

Non è '<<' ma è il '<' e il '<(...) 'operatore, se ricordo bene –

risposta

23

<() si chiama process substitution nel manuale ed è simile a un pipe ma passa un argomento del modulo /dev/fd/63 invece di utilizzare stdin.

< legge l'input da un file denominato sulla riga di comando.

Insieme, questi due operatori funzione esattamente come un tubo, in modo che possa essere riscritta come (comando)

find /bar -name *foo* -print0 | while read line; do 
    ... 
done 
+8

non è la stessa cosa se non si deve iniziare una subshell – knittl

+6

+1 perché si ha il nome corretto per la notazione. Come sottolinea @knittl, non è del tutto identico alla tua riscrittura perché il ciclo verrà eseguito in una sotto-shell, e tutte le modifiche apportate nelle variabili dal ciclo interesseranno solo la sotto-shell, non lo script principale. Puoi affrontarlo reindirizzando l'output di "trova" in "{{while ...; fare ...; fatto; ... resto del copione ...; } '', usando le parentesi per raggruppare l'intero resto dello script - loop e altro materiale - in una singola sotto-shell. –

+1

grazie per quello. Posso sentire il mio cranio espandersi sulla parte del cervello che esegue lo scripting di shell. Avere un termine preciso per google lo rende molto più facile. Ora vado a scoprire cos'è una sottotitola. – stib

-3

L'operatore << introduce un here-document, che accetta l'output di un altro comando come input per il primo comando.

Aggiornamento

Va bene, quindi devono aver aggiunto alcune cose al guscio dall'ultima volta che ho usato 15 anni fa.
Gentilmente disprezzo.

4

< reindirizza a stdin.

<() sembra essere una sorta di un tubo di inversione, come accennato nella pagina:

find /bar -name *foo* -print0 | \ 
while IFS= read -r -d $'\0' file; do 
    dosomethingwith "$file"  # do something with each file 
done 

non funzionerà, perché il ciclo while sarà eseguito in una subshell, e perderai le modifiche apportate nel ciclo

+0

Questa risposta trarrebbe vantaggio da un x-ref per "elaborare la sostituzione" e un URL come http://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution che lo spiega. Il punto chiave è la sotto-shell e le modifiche apportate alle variabili nella sub-shell. L'altro modo di affrontarlo è: "trova ... | { mentre ...; fare ...; fatto; ... resto del copione ...; } ', usando le parentesi per eseguire tutto il resto dello script in una sotto-shell invece del solo ciclo while. –

3

< è sostituzione di processo. Fondamentalmente, crea un tipo speciale di file chiamato "named pipe", quindi reindirizza l'output del comando come named pipe. Ad esempio, supponiamo di voler sfogliare un elenco di file in una directory extra-large. Si potrebbe fare questo:

ls /usr/bin | more 

O questo:

more <(ls /usr/bin) 

Ma non questa:

more $(ls /usr/bin) 

La ragione di ciò diventa chiaro quando si approfondire:

~$ echo $(ls /tmp) 
gedit.maxtothemax.436748151 keyring-e0fuHW mintUpdate orbit-gdm orbit-maxtothemax plugtmp pulse-DE9F3Ei96ibD pulse-PKdhtXMmr18n ssh-wKHyBU1713 virtual-maxtothemax.yeF3Jo 
~$ echo <(ls /tmp) 
/dev/fd/63 
~$ cat <(ls /tmp) 
gedit.maxtothemax.436748151 
keyring-e0fuHW 
mintUpdate 
orbit-gdm 
orbit-maxtothemax 
plugtmp 
pulse-DE9F3Ei96ibD 
pulse-PKdhtXMmr18n 
ssh-wKHyBU1713 
virtual-maxtothemax.yeF3Jo 

/dev/fd/qualunque cosa si comporta come un file di testo con l'output del comando tra parentesi.