Quelle est la différence entre <<, <<< et <<in bash?


103

Quelle est la difference entre <<, <<<et < <in bash?


20
Au moins en ces temps centrés sur Google, il est difficile de rechercher ces opérateurs basés sur des symboles. Existe-t-il un moteur de recherche où vous pouvez insérer "<< <<< <<" et obtenir quelque chose d'utile?
Daniel Griscom le

11
@DanielGriscom Il y a SymbolHound .
Dennis

1
@DanielGriscom Stack Exchange supportait la recherche de symboles, mais quelque chose s'est cassé et personne ne l'a jamais réparé.
Muru

C'est déjà là (et ce depuis presque un an): Quels sont les opérateurs de contrôle et de redirection du shell?
Scott

Réponses:


116

Ici le document

<<est connu comme here-documentstructure. Vous laissez le programme savoir quel sera le texte de fin et, chaque fois que ce séparateur sera vu, le programme lira tout ce que vous lui avez donné en entrée et effectuera une tâche.

Voici ce que je veux dire:

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

Dans cet exemple, nous indiquons au wcprogramme d'attendre une EOFchaîne, puis nous tapons cinq mots, puis EOFnous signalons que nous avons terminé la saisie. En fait, cela ressemble à courir tout wcseul, taper des mots, puis appuyer surCtrlD

En bash, ceux-ci sont implémentés via des fichiers temporaires, généralement sous la forme /tmp/sh-thd.<random string>, alors qu'en tirets, ils sont implémentés sous forme de canaux anonymes. Cela peut être observé via le suivi des appels système avec stracecommande. Remplacez bashpar shpour voir comment /bin/sheffectue cette redirection.

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

Ici la chaîne

<<<est connu comme here-string. Au lieu de taper du texte, vous donnez une chaîne de texte prédéfinie à un programme. Par exemple, avec un tel programme que bcnous pouvons faire bc <<< 5*4pour obtenir simplement une sortie pour ce cas spécifique, il n’est pas nécessaire d’exécuter bc de manière interactive.

Ici, les chaînes de bash sont implémentées via des fichiers temporaires, généralement au format /tmp/sh-thd.<random string>, qui sont ensuite dissociés, leur permettant ainsi d’occuper temporairement de l’espace mémoire, mais ne figurant pas dans la liste des /tmpentrées de répertoires, et existant en tant que fichiers anonymes, qui peuvent encore être référencé via le descripteur de fichier par le shell lui-même, et ce descripteur de fichier étant hérité par la commande puis dupliqué sur le descripteur de fichier 0 (stdin) via une dup2()fonction. Ceci peut être observé via

$ 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

Et via le suivi des appels système (sortie abrégée pour des raisons de lisibilité; notez comment le fichier temporaire est ouvert en tant que fd 3, les données qui y sont écrites, puis il est rouvert avec O_RDONLYflag en tant que fd 4 et plus tard sans lien, puis dup2()sur fd 0, qui est hérité par la catsuite ):

$ 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 +++

Opinion: potentiellement parce que les chaînes utilisent des fichiers texte temporaires, c’est peut-être la raison pour laquelle les chaînes insèrent toujours une nouvelle ligne de fin, puisqu'un fichier texte défini par POSIX doit comporter des lignes qui se terminent par un caractère de nouvelle ligne.

Processus de substitution

Comme l' explique tldp.org ,

La substitution de processus alimente la sortie d'un processus (ou de processus) dans le stdin d'un autre processus.

Donc, en pratique, cela ressemble à la tuyauterie stdout d’une commande à l’autre, par exemple echo foobar barfoo | wc. Mais remarquez: dans la page de manuel bash, vous verrez qu’elle est notée comme <(list). Donc, fondamentalement, vous pouvez rediriger la sortie de plusieurs (!) Commandes.

Remarque: techniquement, lorsque vous dites que < <vous ne faites pas référence à une chose, mais à deux redirection avec une redirection unique <et en mode processus de la sortie <( . . .).

Maintenant que se passe-t-il si nous ne faisons que traiter la substitution?

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

Comme vous pouvez le constater, le shell crée un descripteur de fichier temporaire dans /dev/fd/63lequel le résultat est envoyé (ce qui, selon la réponse de Gilles , est un canal anonyme). Cela signifie <que ce descripteur de fichier redirige comme entrée dans une commande.

Un exemple très simple consisterait à effectuer une substitution de processus de la sortie de deux commandes echo dans wc:

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

Donc, ici, nous faisons en sorte que le shell crée un descripteur de fichier pour toutes les sorties qui se produisent dans la parenthèse et redirige celui-ci en entrée vers wc. Comme prévu, wc reçoit ce flux de deux commandes echo, qui à elles seules produiraient deux lignes, chacune ayant un mot, et de manière appropriée, nous avons 2 mots, 2 lignes et 6 caractères plus deux nouvelles lignes comptées.

Side Note: La substitution de processus peut être considéré comme un bash (une commande ou une structure utilisable dans des coquilles avancées telles que bash, mais non spécifiée par POSIX), mais il a été mis en œuvre dans kshl'existence de bash avant que la page man ksh et cette réponse suggère. Les coquilles aiment tcshet mkshn'ont cependant pas de processus de substitution. Alors, comment pourrions-nous rediriger la sortie de plusieurs commandes dans une autre commande sans substitution de processus? Regroupement plus tuyauterie!

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

Effectivement, c'est la même chose que l'exemple ci-dessus. Cependant, cela est différent du remplacement de processus, puisque nous faisons stdout de tout le sous-shell et stdin de wc lié au tuyau . D'autre part, la substitution de processus fait en sorte qu'une commande lise un descripteur de fichier temporaire.

Donc, si nous pouvons faire un regroupement avec une tuyauterie, pourquoi avons-nous besoin d'une substitution de processus? Parce que parfois nous ne pouvons pas utiliser de tuyauterie. Prenons l'exemple ci-dessous - comparaison des résultats de deux commandes avec diff(ce qui nécessite deux fichiers, et dans ce cas, nous lui donnons deux descripteurs de fichier)

diff <(ls /bin) <(ls /usr/bin)

7
< <est utilisé quand on obtient stdin d'une substitution de processus . Une telle commande pourrait ressembler à : cmd1 < <(cmd2). Par exemple,wc < <(date)
John1024 le

4
Oui, la substitution de processus est prise en charge par bash, zsh et AT & T ksh {88,93} mais pas par pdksh / mksh.
John1024

2
< < ce n'est pas une chose en soi, dans le cas d'une substitution de processus, c'est juste un <suivi par quelque chose d'autre qui commence par l'utilisateur<
user253751 le

1
@ muru Pour autant que je sache, <<<a d'abord été implémenté par le port Unix de Plan 9 shell rc, puis adopté plus tard par zsh, bash et ksh93. Je n'appellerais pas cela un bashisme.
Juillet

3
Un autre exemple de l' endroit où la tuyauterie ne peut pas être utilisé: echo 'foo' | read; echo ${REPLY}ne pas revenir foo, car readon a commencé dans un sous-shell - la tuyauterie commence un sous-shell. Cependant, read < <(echo 'foo'); echo ${REPLY}renvoie correctement foo, car il n'y a pas de sous-shell.
Paddy Landau

26

< < est une erreur de syntaxe:

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

< <()Le processus substitution ( <()) est-il combiné à la redirection ( <):

Un exemple artificiel:

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

Avec la substitution de processus, le chemin d'accès au descripteur de fichier est utilisé comme un nom de fichier. Si vous ne voulez pas (ou ne pouvez pas) utiliser directement un nom de fichier, vous combinez la substitution de processus avec la redirection.

Pour être clair, il n'y a pas d' < <opérateur.


Je comprends par votre réponse que, <<() plus utile que <() non?
solfish

1
@solfish ressemble <()à un nom de fichier, il est donc généralement utile: il < <()remplace le stdin s'il n'est pas nécessaire. Dans wc, ce dernier se trouve être plus utile. Cela pourrait être moins utile ailleurs
muru

12

< <est une erreur de syntaxe, vous voulez probablement dire command1 < <( command2 )qui est une simple redirection d’entrée suivie d’un processus de substitution et qui est très similaire mais n’équivaut pas à:

command2 | command1

La différence en supposant que vous exécutez bashest command1exécutée dans un sous-shell dans le deuxième cas, alors qu'elle est exécutée dans le shell actuel dans le premier. Cela signifie que les variables définies command1ne seront pas perdues avec la variante de substitution de processus.


11

< <donnera une erreur de syntaxe. L'utilisation appropriée est la suivante:

Expliquer à l'aide d'exemples:

Exemple pour < <():

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

Dans l'exemple ci-dessus, l'entrée dans la boucle while proviendra de la lscommande qui peut être lue ligne par ligne et echoed dans la boucle.

<()est utilisé pour la substitution de processus. Vous trouverez plus d’informations et d’exemples <()sur ce lien:

Processus de substitution et pipe

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.