Quelle est la difference entre <<
, <<<
et < <
in bash?
Quelle est la difference entre <<
, <<<
et < <
in bash?
Réponses:
Ici le 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 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 wc
programme d'attendre une EOF
chaîne, puis nous tapons cinq mots, puis EOF
nous signalons que nous avons terminé la saisie. En fait, cela ressemble à courir tout wc
seul, 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 strace
commande. Remplacez bash
par sh
pour voir comment /bin/sh
effectue 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 bc
nous pouvons faire bc <<< 5*4
pour 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 /tmp
entré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_RDONLY
flag en tant que fd 4 et plus tard sans lien, puis dup2()
sur fd 0, qui est hérité par la cat
suite ):
$ 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/63
lequel 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 ksh
l'existence de bash avant que la page man ksh et cette réponse suggère. Les coquilles aiment tcsh
et mksh
n'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)
< <
est utilisé quand on obtient stdin d'une substitution de processus . Une telle commande pourrait ressembler à : cmd1 < <(cmd2)
. Par exemple,wc < <(date)
< <
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<
<<<
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.
echo 'foo' | read; echo ${REPLY}
ne pas revenir foo
, car read
on 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.
< <
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.
<()
à 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
< <
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 bash
est command1
exé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 command1
ne seront pas perdues avec la variante de substitution de processus.
< <
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 ls
commande qui peut être lue ligne par ligne et echo
ed dans la boucle.
<()
est utilisé pour la substitution de processus. Vous trouverez plus d’informations et d’exemples <()
sur ce lien: