Che cosa è esattamente <() in bash (e = () in zsh)?


36

Sono abbastanza a mio agio con Bash, ma recentemente sono finito in una sostituzione che non conoscevo.

Cosa c'è esattamente <(<command>)in bash? Come si confronta con =(<command>)in zsh?

Capisco che questo ha qualcosa a che fare con i descrittori di file predefiniti. Nel mio computer

echo <()

ritorna /proc/self/fd/11, che ho scoperto essere una copia della sceneggiatura STDOUT, ma questo mi sembra ancora abbastanza confuso.

Risposte:


52

Questo si chiama sostituzione del processo.

La <(list)sintassi è supportata da entrambi bashe zsh. Fornisce un modo per passare l'output di un comando ( list) a un altro comando quando |non è possibile utilizzare una pipe ( ). Ad esempio, quando un comando non supporta l'input STDINo è necessario l'output di più comandi:

diff <(ls dirA) <(ls dirB)

<(list)collega l'output di listcon un file in /dev/fd, se supportato dal sistema, altrimenti viene utilizzato un nome pipe (FIFO) (che dipende anche dal supporto del sistema; nessuno dei due manuali dice cosa succede se entrambi i meccanismi non sono supportati, presumibilmente si interrompe con un errore). Il nome del file viene quindi passato come argomento sulla riga di comando.


zshsupporta inoltre la =(list)sostituzione possibile per <(list). Con =(list)un file temporaneo viene utilizzato al posto del file in /dev/fdo di un FIFO. Può essere usato come sostituto <(list)se il programma deve cercare nell'output.

Secondo il manuale ZSH potrebbero esserci anche altri problemi con il <(list)funzionamento:

Il =modulo è utile in quanto l' /dev/fdimplementazione sia della pipe denominata che degli <(...)svantaggi. Nel primo caso, alcuni programmi potrebbero chiudere automaticamente il descrittore di file in questione prima di esaminare il file dalla riga di comando, in particolare se ciò è necessario per motivi di sicurezza come quando il programma esegue setuid. Nel secondo caso, se il programma in realtà non apre il file, la subshell che tenta di leggere o scrivere sulla pipe (in una tipica implementazione, sistemi operativi diversi potrebbero avere comportamenti diversi) si bloccherà per sempre e dovrà essere uccisa esplicitamente . In entrambi i casi, la shell fornisce effettivamente le informazioni usando una pipe, in modo che i programmi che prevedono di cercare (vedi la pagina man lseek(2)) sul file non funzionino.


Questo mi ha aiutato a capire perché MacOS pfctl -f <(echo "pf rules")avrebbe detto un descrittore di file errato. usando zsh e = (echo "regole pf") invece funziona.
johnnyB,

9

Nota, questa è una risposta bash, non zsh.

Ci sono casi in bash in cui non puoi usare le pipe:

some_command | some_other_command

poiché i tubi introducono sottotitoli per ciascun componente della conduttura, quando i sottotitoli escono, tutti gli effetti collaterali su cui si fa affidamento scompaiono. Ad esempio, questo esempio inventato:

cat file | while read line; do ((count++)); done
echo $count

visualizzerà una riga vuota, poiché la $countvariabile non esiste nella shell corrente.

Una sostituzione del processo bash ti consente di evitare questo enigma consentendoti di leggere dall'output "some_command" come faresti da un file

while read line; do ((count++)); done < <(cat file)
# ....................................1.2
echo $count   # the variable *does* exist in the current shell

(1) è un reindirizzamento di input normale. (2) è l'inizio della <()sintassi di sostituzione del processo.


2
= (cmdlist) in zsh ha quasi lo stesso effetto di <(cmdlist) in bash ma crea (ed elimina quando pronto) un file temporaneo con l'output di cmdlist per il reindirizzamento. Questo è utile quando la ricerca è potenzialmente eseguita nel programma. <(cmdlist) è anche conosciuto da zsh.
Gombai Sándor,
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.