Pourquoi «sort <(ls -l)» `fonctionne mais` sort <(ls -l) `échoue?


32

Aujourd'hui, j'apprends quelque chose sur fifo avec cet article: Introduction aux pipes nommées , qui est mentionné cat <(ls -l).

J'ai fait quelques expériences en utilisant sort < (ls -l), ce qui fait apparaître une erreur:

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

Ensuite, j'ai découvert que j'avais mal ajouté un espace supplémentaire dans la commande.

Mais, pourquoi cette commande supplémentaire conduira à cet échec? Pourquoi le symbole de redirection doit-il être proche de (?


Il convient de noter que * nix shells divise les éléments en fonction des espaces, ce qui crée les jetons mentionnés par Alec.
poussins

Réponses:


45

Parce que ce n'est pas un <, c'est un <()qui est complètement différent. C'est ce qu'on appelle la substitution de processus . Il s'agit d'une fonctionnalité de certains shells qui vous permet d'utiliser la sortie d'un processus en tant qu'entrée pour un autre.

Les opérateurs >et <redirigent la sortie vers et l’entrée depuis les fichiers . L' <()opérateur traite des commandes (processus), pas des fichiers. Quand tu cours

sort < (ls)

Vous essayez d'exécuter la commande lsdans un sous-shell (c'est ce que signifient les parenthèses), puis de transmettre ce sous-shell en tant que fichier d'entrée sort. Ceci, cependant, n'est pas une syntaxe acceptée et vous obtenez l'erreur que vous avez vue.


3
Votre réponse est bonne, mais then sort is attempting to read the subshell as its input file→ c'est évidemment faux, car Bash n'analysera même pas la syntaxe. Ni est lsni sortest réellement exécuté.
sleblanc

1
@sebleblanc fair point, a reformulé la réponse, merci.
terdon

1
Il n'y a pas de sous-shell dans ce cas. < (ls)n'est pas un jeton valide ici.
jeudi

@cuonglm no, car bash le traite comme une erreur de syntaxe. Mon point est que (ls)cela fonctionnerait lsdans un sous-shell.
terdon

22

Parce que c'est comme ça que ça se passe.

<(...)in bashest la syntaxe pour la substitution de processus. Il est copié du même opérateur dans ksh.

<, (, ), |, &, ;Sont des jetons lexicaux spéciaux bashqui sont utilisés pour former des opérateurs spéciaux dans différentes combinaisons. <, <(, <<, <&... ont chacun leur rôle. <est pour la redirection. <file, < fileredirigerait l’entrée d’un fichier. <'(file)'redirige l'entrée d'un fichier appelé (file), mais <(file)est un opérateur différent qui n'est pas un opérateur de redirection.

< (file)serait <suivi de (file). Dans ce contexte, dans bash, (file)n'est pas valide. (...)peut être valide en tant que jeton unique dans certains contextes tels que:

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

Mais pas dans

sort < (cmd)

Dans la fishcoquille, c'est différent. In fish, (...)est utilisé pour la substitution de commande (l'équivalent de $(...)in bash). Et <est destiné à la redirection d’entrée comme dans les shells Bourne-like.

Alors dans fish:

sort <(echo file)

serait la même chose que:

sort < (echo file)

C'est:

sort < file

Mais c'est quelque chose de complètement différent de bashla substitution de processus.

Dans le yashshell, un autre shell POSIX <(...)n’est pas destiné à la substitution de processus, mais à la redirection de processus.

Là dedans,

sort <(ls -l)

Court pour:

sort 0<(ls -l)

est un opérateur de redirection. C'est plus ou moins équivalent à:

ls -l | sort

Alors que dans bash, le <(ls -l)est étendu au chemin d'un tuyau, il ressemble donc beaucoup à:

ls -l | sort /dev/fd/0

Dans zsh, (...)est surchargé en tant qu'opérateur de globbing ( (*.txt|*.png)développerait les fichiers txtet les pngfichiers) et en tant que qualificateur de globes ( *(/)par exemple, les fichiers de répertoires).

Dans zsh, dans:

sort < (ls -l)

Cela (ls -l)serait traité comme un qualificatif global. Le lqualificatif glob est de faire correspondre le nombre de liens et attend un nombre après l(comme dans la ls -ld ./*(l2)liste des fichiers avec 2 liens), c'est pourquoi vous obtenez une zsh: number expectederreur.

sort < (w)aurait donné une zsh: no matches found: (w)erreur à la place car (w)correspond aux fichiers avec un nom vide qui sont en écriture.

sort < (w|cat)aurait trié le contenu des fichiers wet / ou du catrépertoire en cours ...


pourquoi sort < $(ls -l)donne cette erreur:bash: $(ls -l): ambiguous redirect
Edward Torvalds

@edwardtorvalds, car $(ls -l)s'étend à plus d'un mot. Utilisez des guillemets pour empêcher split + glob ( sort < "$(echo file)"). Notez que le comportement ou bashdiffère de celui de POSIX sh dans le fait que bash effectue cette division + glob là aussi bien quand il n’est pas interactif (pas quand on l’appelle comme shsi).
Stéphane Chazelas

en regardant, ls -l | sort /dev/fd/0je peux dire que la sortie de ls -lest stockée dans /dev/fd/0et que la sortcommande la lit pour donner la sortie souhaitée. J'utilise tail -f --retry /dev/fd/0pour surveiller ce fichier mais je n'obtiens aucune sortie. Pourquoi? Comment puis-je lire ce fichier?
Edward Torvalds le

Dans le poisson, vous pouvez utiliser (foo | psub)pour obtenir une substitution du processus d’entrée; il n'y a pas encore de substitut (ha) pour la substitution du processus de sortie.
Zanchey
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.