Question Quelle est la différence entre <<, <<< et <

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


71
2017-09-27 07:42


origine


Au moins en ces temps centrés sur Google, il est difficile de rechercher ces opérateurs basés sur des symboles. Y at-il un moteur de recherche où vous pouvez brancher "<< <<< <<" et obtenir quelque chose d’utile? - Daniel Griscom
@DanielGriscom Il y a SymbolHound. - Dennis
@DanielGriscom Stack Exchange supportait les symboles de recherche, mais quelque chose s'est cassé et personne ne l'a jamais réparé. - muru
C'est déjà là (et cela fait presque un an): Quels sont les opérateurs de contrôle et de redirection du shell? - Scott


Réponses:


Ici document

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

Voici ce que je veux dire:

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

Dans cet exemple, nous disons wc programme pour attendre EOF chaîne, puis tapez cinq mots, puis tapez EOF pour signaler que nous avons fini de donner notre avis. En fait, c'est similaire à la course wc par lui-même, en tapant des mots, puis en appuyant sur Ctrl

Dans bash ceux-ci sont implémentés via des fichiers temporaires, généralement sous la forme /tmp/sh-thd.<random string>, tandis que dans le tableau de bord ils sont mis en œuvre en tant que tuyaux anonymes. Cela peut être observé via des appels système de suivi avec strace commander. Remplacer bash avec sh pour voir comment /bin/sh effectue cette redirection.

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

Ici string

<<< est connu comme here-string . Au lieu de taper du texte, vous donnez une chaîne de texte pré-établie à un programme. Par exemple, avec un programme tel que bc nous pouvons faire bc <<< 5*4 pour obtenir juste la sortie pour ce cas spécifique, pas besoin d'exécuter bc interactivement.

Les chaînes en bash sont implémentées via des fichiers temporaires, généralement au format /tmp/sh-thd.<random string>, qui sont ensuite dissociés, ce qui les oblige à occuper temporairement un espace mémoire mais ne figure pas dans la liste des /tmp les entrées de répertoire, et existent effectivement en tant que fichiers anonymes, qui peuvent toujours être référencés via le descripteur de fichier par le shell lui-même, et ce descripteur de fichier hérité par la commande puis dupliqué sur le descripteur de fichier 0 (stdin) via dup2() fonction. Cela 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 traçage de syscalls (sortie raccourcie pour la lisibilité; remarquez comment le fichier temp est ouvert en tant que fd 3, les données qui y sont écrites, puis il est rouvert avec O_RDONLY flag comme fd 4 et plus tard dissocié, puis dup2() sur fd 0, qui est hérité par cat plus tard ):

$ 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 ici les chaînes utilisent des fichiers texte temporaires, c'est la raison possible pour laquelle les chaînes insèrent toujours une nouvelle ligne, puisque le fichier texte de Définition POSIX doit avoir des lignes qui se terminent par un caractère de nouvelle ligne.

Substitution de processus 

Comme tldp.org explique,

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

Donc, en fait, cela est similaire à la tuyauterie stdout d'une commande à l'autre, par ex. echo foobar barfoo | wc . Mais remarquez: dans le page de manuel bash vous verrez qu'il est noté <(list). Donc, fondamentalement, vous pouvez rediriger la sortie de plusieurs commandes (!).

Remarque: techniquement quand vous dites < < vous ne faites pas référence à une chose, mais deux redirection avec single < et réorienter les processus de sortie de <( . . .).

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

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

Comme vous pouvez le voir, le shell crée un descripteur de fichier temporaire /dev/fd/63 où la sortie va (qui selon La réponse de Gilles, est un tuyau anonyme). Cela signifie < redirige ce descripteur de fichier en entrée dans une commande.

Un exemple très simple serait de faire en sorte que la substitution de processus de la sortie de deux commandes d'écho dans wc:

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

Donc, ici, nous faisons en sorte que shell crée un descripteur de fichier pour toutes les sorties qui apparaissent dans la parenthèse et redirige celui-ci en entrée vers wc Comme prévu, wc reçoit ce flux à partir de deux commandes d'écho, ce qui en soi produirait 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.

Note latérale: La substitution de processus peut être appelée bashisme (une commande ou une structure utilisable dans des shells avancés comme bash, mais non spécifié par POSIX), mais il a été implémenté dans ksh avant l'existence de bash comme page de manuel de ksh et cette réponse suggérer. Des coquillages tcsh et mksh cependant, ne pas avoir de substitution de processus. Alors, comment pouvons-nous rediriger la sortie de plusieurs commandes vers une autre commande sans substitution de processus? Grouper plus la tuyauterie!

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

En effet, cela est identique à l'exemple ci-dessus. Cependant, ceci est différent de la substitution de processus, puisque nous faisons stdout de tout le sous-shell et de stdin de wc  lié au tuyau. D'autre part, la substitution de processus permet à une commande de lire un descripteur de fichier temporaire.

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

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

83
2017-09-27 07:56



< < est utilisé quand on obtient stdin d'un substitution de processus. Une telle commande pourrait ressembler à ceci: cmd1 < <(cmd2). Par exemple, wc < <(date) - John1024
Oui, la substitution de processus est prise en charge par bash, zsh et AT & T ksh {88,93} mais pas par pdksh / mksh. - John1024
< <  n'est pas une chose en soi, dans le cas de la substitution de processus, c'est juste un < suivie par quelque chose d'autre qui se passe pour commencer < - immibis
@muru Autant que je sache, <<< a été implémenté pour la première fois par le port Unix de Plan 9 rc shell puis adopté plus tard par zsh, bash et ksh93. Je ne l'appellerais pas alors un bashisme. - jlliagre
Un autre exemple de tuyauterie ne peut pas être utilisé: echo 'foo' | read; echo ${REPLY} volonté ne pas revenir foo, car read est démarré dans un sous-shell - le piping démarre un sous-shell. cependant, read < <(echo 'foo'); echo ${REPLY} renvoie correctement foo, car il n'y a pas de sous-shell. - Paddy Landau


< < est une erreur de syntaxe:

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

< <() est substitution de processus (<()) combiné avec 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 de < < opérateur.


22
2017-09-27 08:05



Je reçois par ta réponse que <<() plus utile que <() non? - solfish
@solfish <() donne une chose comme un nom de fichier, donc c'est plus généralement utile - < <() remplace le stdin où cela pourrait ne pas être nécessaire. Dans wc, ce dernier se trouve être plus utile. Il pourrait être moins utile ailleurs - muru


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

command2 | command1

La différence en supposant que vous courez bash est command1 est exécuté dans un sous-shell dans le second cas alors qu'il est exécuté dans le shell actuel du premier. Cela signifie que les variables définies dans command1 ne serait pas perdu avec la variante de substitution de processus.


10
2017-09-27 08:09





< < 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 du ls commande qui peut être lue ligne par ligne et echoed dans la boucle.

<() est utilisé pour la substitution de processus. Plus d'informations et exemple pour <()peut être trouvé à ce lien:

Substitution de processus et tuyau


8
2017-09-27 08:06