Perché `sort <(ls -l)` funziona ma `sort <(ls -l)` fallisce?


32

Oggi sto imparando qualcosa sul FIFO con questo articolo: Introduzione ai Named Pipes , che menziona cat <(ls -l).

Ho fatto alcuni esperimenti usando sort < (ls -l), che fa apparire un errore:

-bash: syntax error near unexpected token `('`

Poi ho scoperto di aver erroneamente aggiunto uno spazio aggiuntivo nel comando.

Ma perché questo comando aggiuntivo porterà a questo fallimento? Perché il simbolo di reindirizzamento deve essere vicino al simbolo (?


Va notato che * nix shells divide le cose in base allo spazio bianco che crea i token menzionati da Alec.
pulcini,

Risposte:


45

Perché quello non è un <, è un <()che è completamente diverso. Questa si chiama sostituzione di processo , è una caratteristica di alcune shell che consente di utilizzare l'output di un processo come input per un altro.

Gli operatori >e <reindirizzano l'output e l'input dai file . L' <()operatore si occupa dei comandi (processi), non dei file. Quando corri

sort < (ls)

Stai tentando di eseguire il comando lsin una subshell (questo è il significato delle parentesi), quindi di passare quella subshell come file di input a sort. Questo, tuttavia, non è una sintassi accettata e viene visualizzato l'errore visualizzato.


3
La tua risposta è buona, ma then sort is attempting to read the subshell as its input file→ questo è ovviamente sbagliato, poiché Bash non analizzerà nemmeno la sintassi. Né lssortviene effettivamente eseguito.
Slitta

1
@sebleblanc punto giusto, riformulato la risposta, grazie.
Terdon

1
Non ci sono sotto-shell in questo caso. < (ls)non è un token valido qui.
cuonglm,

@cuonglm no, perché bash lo considera un errore di sintassi. Il mio punto è che (ls)verrebbe eseguito lsin una subshell.
terdon

22

Perché è così che deve essere.

<(...)in bashè la sintassi per la sostituzione del processo. Viene copiato dallo stesso operatore in ksh.

<, (, ), |, &, ;Sono token lessicali speciali bashche sono usati per formare operatori speciali in diverse combinazioni. <, <(, <<, <&... hanno ciascuno il proprio ruolo. <è per il reindirizzamento. <file, < filereindirizzerebbe l'input da un file. <'(file)'reindirizzerebbe l'input da un file chiamato (file), ma <(file)è un operatore diverso che non è un operatore di reindirizzamento.

< (file)sarebbe <seguito da (file). In tale contesto, in bash, (file)non è valido. (...)può essere valido come token singolo in alcuni contesti come:

(sub shell)
func () {
  ...
}
var=(foo bar)

Ma non dentro

sort < (cmd)

Nella fishshell, è diverso. Nelfish , (...)è per la sostituzione dei comandi (l'equivalente di $(...)in bash). Ed <è per il reindirizzamento dell'input come nelle shell tipo Bourne.

Quindi dentro fish :

sort <(echo file)

sarebbe lo stesso di:

sort < (echo file)

Questo è:

sort < file

Ma è qualcosa di completamente diverso dalla bashsostituzione del processo.

Nella yashshell, un'altra shell POSIX, <(...)non è per la sostituzione di processo ma per reindirizzamento dei processi

Lì dentro,

sort <(ls -l)

Corto per:

sort 0<(ls -l)

è un operatore di reindirizzamento. È più o meno equivalente a:

ls -l | sort

Mentre in bash, <(ls -l)viene espanso nel percorso di una pipe, quindi è più simile a:

ls -l | sort /dev/fd/0

In zsh, (...)viene sovraccaricato come operatore globbing ( (*.txt|*.png)si espanderebbe a txtepng file) e come qualificatore glob ( *(/)ad esempio si espande in file di directory).

In zsh, in:

sort < (ls -l)

Che (ls -l)sarebbero trattati come un qualificatore glob. Il lqualificatore glob deve corrispondere al numero di collegamenti e si aspetta un numero dopo l(come in ls -ld ./*(l2)sarebbe elencare i file con 2 collegamenti), quindi è per questo che si ottiene un zsh: number expectederrore lì.

sort < (w)avrebbe invece dato un zsh: no matches found: (w)errore in quanto (w)corrisponde ai file con nome vuoto che sono scrivibili.

sort < (w|cat)avrebbe ordinato il contenuto dei file we / o catnella directory corrente ...


perché sort < $(ls -l)dà questo errore:bash: $(ls -l): ambiguous redirect
Edward Torvalds,

@edwardtorvalds, perché si $(ls -l)espande in più di una parola. Usa le virgolette per evitare split + glob ( sort < "$(echo file)"). Si noti che il comportamento o bashdifferisce da quello di POSIX sh in quella bash fa dividere anche lì + glob quando non interattivo (non quando chiamato come shse).
Stéphane Chazelas,

guardando ls -l | sort /dev/fd/0posso dire che l'output di ls -lè archiviato /dev/fd/0e il sortcomando lo legge per fornire l'output desiderato. Sto usando tail -f --retry /dev/fd/0per monitorare quel file ma non ottengo alcun output. perché? come posso leggere quel file?
Edward Torvalds,

Nei pesci, è possibile utilizzare (foo | psub)per ottenere la sostituzione del processo di input; non esiste ancora un sostituto (ha) per la sostituzione del processo di output.
Zanchey,
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.