Qual è la differenza tra e in bash?

71

Qual è la differenza tra << , <<< e < < in bash?

    
posta Searene 27.09.2015 - 09:42

4 risposte

82

Qui documento

<< è noto come here-document struttura. Tu fai sapere al programma quale sarà il testo finale e ogni volta che quel delimitatore viene visto, il programma leggerà tutte le cose che hai dato al programma come input ed eseguirà un compito su di esso.

Ecco cosa intendo:

$ wc << EOF
> one two three
> four five
> EOF
 2  5 24

In questo esempio diciamo al programma wc di aspettare EOF string, quindi digitare cinque parole e poi digitare EOF per segnalare che abbiamo finito di dare input. In effetti, è simile all'esecuzione di wc di per sé, digitando le parole, quindi premendo Ctrl D

In bash questi sono implementati tramite i file temporanei, solitamente nella forma /tmp/sh-thd.<random string> , mentre nel trattino sono implementati come pipe anonime. Ciò può essere osservato tramite le chiamate di sistema di traccia con il comando strace . Sostituisci bash con sh per vedere come /bin/sh esegue questo reindirizzamento.

$ strace -e open,dup2,pipe,write -f bash -c 'cat <<EOF
> test
> EOF'

Qui stringa

<<< è noto come here-string . Invece di digitare il testo, si fornisce una stringa di testo pre-creata a un programma. Ad esempio, con un programma come bc possiamo fare bc <<< 5*4 per ottenere solo l'output per quel caso specifico, non è necessario eseguire bc in modo interattivo.

Le stringhe qui in bash sono implementate tramite file temporanei, di solito nel formato /tmp/sh-thd.<random string> , che vengono successivamente scollegati, facendo in modo che occupino temporaneamente dello spazio di memoria ma non si visualizzino nell'elenco delle voci di directory /tmp , e esistono effettivamente come file anonimi, che possono ancora essere referenziati tramite il descrittore di file dalla shell stessa e che il descrittore di file viene ereditato dal comando e successivamente duplicato sul descrittore di file 0 (stdin) tramite la funzione dup2() . Questo può essere osservato tramite

$ ls -l /proc/self/fd/ <<< "TEST"
total 0
lr-x------ 1 user1 user1 64 Aug 20 13:43 0 -> /tmp/sh-thd.761Lj9 (deleted)
lrwx------ 1 user1 user1 64 Aug 20 13:43 1 -> /dev/pts/4
lrwx------ 1 user1 user1 64 Aug 20 13:43 2 -> /dev/pts/4
lr-x------ 1 user1 user1 64 Aug 20 13:43 3 -> /proc/10068/fd

E tracciando syscalls (output abbreviato per leggibilità, nota come il file temp è aperto come fd 3, i dati scritti su di esso, poi viene riaperto con O_RDONLY flag come fd 4 e successivi non collegati, quindi dup2() su fd 0, che è ereditato da cat più tardi):

$ strace -f -e open,read,write,dup2,unlink,execve bash -c 'cat <<< "TEST"'
execve("/bin/bash", ["bash", "-c", "cat <<< \"TEST\""], [/* 47 vars */]) = 0
...
strace: Process 10229 attached
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
[pid 10229] write(3, "TEST", 4)         = 4
[pid 10229] write(3, "\n", 1)           = 1
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDONLY) = 4
[pid 10229] unlink("/tmp/sh-thd.uhpSrD") = 0
[pid 10229] dup2(4, 0)                  = 0
[pid 10229] execve("/bin/cat", ["cat"], [/* 47 vars */]) = 0
...
[pid 10229] read(0, "TEST\n", 131072)   = 5
[pid 10229] write(1, "TEST\n", 5TEST
)       = 5
[pid 10229] read(0, "", 131072)         = 0
[pid 10229] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=10229, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

Opinione: potenzialmente perché qui le stringhe fanno uso di file di testo temporanei, è il possibile motivo per cui qui le stringhe inseriscono sempre una nuova riga finale, poiché il file di testo definizione POSIX deve avere linee che terminano con carattere di nuova riga.

Sostituzione processo

Come tldp.org spiega,

  

La sostituzione processo alimenta l'output di un processo (o processi) in   lo stdin di un altro processo.

Quindi in effetti questo è simile al piping stdout di un comando all'altro, ad es. %codice% . Ma attenzione: nella bash manpage vedrai che è denotato come echo foobar barfoo | wc . Quindi in pratica è possibile reindirizzare l'output di più comandi (!).

Nota: tecnicamente quando dici <(list) non ti riferisci a una cosa, ma due reindirizzamenti con% < < e reindirizzamento di processo dell'output da < .

Ora cosa succede se elaboriamo semplicemente la sostituzione?

$ echo <(echo bar)
/dev/fd/63

Come puoi vedere, la shell crea il descrittore di file temporaneo <( . . .) dove va l'output (che secondo la risposta di Gilles , è un tubo anonimo). Ciò significa che /dev/fd/63 reindirizza il descrittore di file come input in un comando.

Quindi un esempio molto semplice potrebbe essere la sostituzione del processo di output da due comandi echo in wc:

$ wc < <(echo bar;echo foo)
      2       2       8

Quindi facciamo in modo che la shell crei un descrittore di file per tutto l'output che si verifica nelle parentesi e reindirizzalo come input a < . Come previsto, wc riceve quel flusso da due comandi echo, che di per sé genererebbero due righe , ognuno con una parola e in modo appropriato abbiamo 2 parole, 2 righe e 6 caratteri più due nuove righe contate.

Nota a margine: la sostituzione del processo può essere definita come un bashism (un comando o una struttura utilizzabile in shell avanzate come wc , ma non specificato da POSIX), ma è stato implementato in bash prima dell'esistenza di bash come pagina ksh man e questa risposta suggerisce. Gusci come ksh e tcsh tuttavia non hanno sostituzione di processo. Quindi, come potremmo andare in giro a reindirizzare l'output di più comandi in un altro comando senza la sostituzione del processo? Raggruppamento più piping!

$ (echo foo;echo bar) | wc
      2       2       8

In effetti questo è lo stesso dell'esempio precedente, Tuttavia, questo è diverso sotto la copertura dalla sostituzione del processo, poiché facciamo lo stdout dell'intera subshell e dello stdin di mksh collegato alla pipe . D'altra parte, la sostituzione del processo fa sì che un comando legga un descrittore di file temporaneo.

Quindi, se possiamo fare il raggruppamento con le tubature, perché abbiamo bisogno della sostituzione del processo? Perché a volte non possiamo usare le tubazioni. Considera l'esempio seguente: confronta gli output di due comandi con wc (che richiede due file, e in questo caso gli stiamo dando due descrittori di file)

diff <(ls /bin) <(ls /usr/bin)
    
risposta data Sergiy Kolodyazhnyy 27.09.2015 - 09:56
22

< < è un errore di sintassi:

$ cat < <
bash: syntax error near unexpected token '<'

< <() è sostituzione del processo ( <() ) combinato con reindirizzamento ( < ):

Un esempio forzato:

$ wc -l < <(grep ntfs /etc/fstab)
4
$ wc -l <(grep ntfs /etc/fstab)
4 /dev/fd/63

Con la sostituzione del processo, il percorso del descrittore di file viene utilizzato come un nome file. Nel caso in cui non si voglia (o non si possa) utilizzare direttamente un nome file, si combina la sostituzione del processo con il reindirizzamento.

Per essere chiari, non esiste un operatore < < .

    
risposta data muru 27.09.2015 - 10:05
10

< < è un errore di sintassi, probabilmente si intende command1 < <( command2 ) che è un semplice reindirizzamento dell'input seguito da una sostituzione del processo ed è molto simile ma non equivalente a:

command2 | command1

La differenza assumendo che tu stia correndo bash è command1 viene eseguito in una sottoshell nel secondo caso mentre viene eseguito nella shell corrente nella prima. Ciò significa che le variabili impostate in command1 non andranno perse con la variante di sostituzione del processo.

    
risposta data jlliagre 27.09.2015 - 10:09
8

< < darà un errore di sintassi. L'uso corretto è il seguente:

Spiegando con l'aiuto di esempi:

Esempio di < <() :

while read line;do
   echo $line
done< <(ls)

Nell'esempio sopra, l'input del ciclo while verrà dal comando ls che può essere letto riga per riga e echo ed nel ciclo.

<() viene utilizzato per la sostituzione del processo. Ulteriori informazioni ed esempi per <() sono disponibili a questo link:

Sostituzione e pipe di processo

    
risposta data snoop 27.09.2015 - 10:06

Leggi altre domande sui tag