J’avais besoin d’écrire un script pour entrer une entrée multi-ligne dans un programme ( psql
).
Après un peu de recherche sur Google, j’ai trouvé les travaux de syntaxe suivants:
cat << EOF | psql ---params BEGIN; `pg_dump ----something` update table .... statement ...; END; EOF
Cela construit correctement la chaîne multiligne (de BEGIN;
à END;
inclus) et la transforme en entrée de psql
.
Mais je ne sais pas comment et pourquoi cela fonctionne, quelqu’un peut-il expliquer?
Je me réfère principalement à cat << EOF
, je sais >
sorties à un fichier, >>
ajoute à un fichier, <
lit l’entrée à partir du fichier.
Que fait <<
exactement?
Et y a-t-il une page de manuel pour cela?
Cela s’appelle le format heredoc pour fournir une chaîne dans stdin. Voir https://en.wikipedia.org/wiki/Here_document#Unix_shells pour plus de détails.
De l’ man bash
:
Ici des documents
Ce type de redirection demande au shell de lire les entrées de la source en cours jusqu’à ce qu’une ligne contenant uniquement des mots (sans espaces de fin) soit affichée.
Toutes les lignes lues jusqu’à ce point sont ensuite utilisées comme entrée standard pour une commande.
Le format des documents ici est:
<<[-]word here-document delimiter
Aucune extension de paramètre, substitution de commande, expansion arithmétique ou extension de chemin n'est effectuée sur word . Si des caractères dans un mot sont cités, le délimiteur est le résultat de la suppression de citation sur le mot , et les lignes dans le document ici ne sont pas développées. Si le mot n'est pas cité, toutes les lignes du document sont soumises à l'extension des parameters, à la substitution de commandes et à l'expansion arithmétique. Dans ce dernier cas, la séquence de caractères
\
est ignorée et\
doit être utilisé pour citer les caractères\
,$
et`
.Si l'opérateur de redirection est
<<-
, tous les caractères de tabulation en tête sont supprimés des lignes d'entrée et de la ligne contenant le délimiteur . Cela permet de mettre en retrait les documents ici dans les scripts shell.
La syntaxe cat <
cat < dans Bash:
$ sql=$(cat <
La variable $sql
contient désormais les caractères de nouvelle ligne. Vous pouvez vérifier avec echo -e "$sql"
.
$ cat < print.sh #!/bin/bash echo \$PWD echo $PWD EOF
Le fichier print.sh
contient maintenant:
#!/bin/bash echo $PWD echo /home/user
$ cat <
Le fichier b.txt
contient des lignes bar
et baz
. La même sortie est imprimée sur stdout
.
Dans votre cas, “EOF” est appelé “Here Tag”. En gros <
Here
. Vous pouvez nommer cette balise comme vous le souhaitez, c'est souvent EOF
ou STOP
.
Quelques règles sur les tags Here:
Exemple:
$ cat >> test < Hello world HERE <-- Not by itself on a separate line -> not considered end of ssortingng > This is a test > HERE <-- Leading space, so not considered end of string > and a new line > HERE <-- Now we have the end of the string
kennytm a cité l’ man bash
, mais la plus grande partie est aussi POSIX 7: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04 :
Les opérateurs de redirection “<<" et "<< -" permettent à la fois de rediriger des lignes contenues dans un fichier d'entrée de shell, appelé "here-document", à l'entrée d'une commande.
Le document ici doit être traité comme un mot unique qui commence après le suivant et continue jusqu’à ce qu’il y ait une ligne contenant uniquement le délimiteur et a, sans caractères entre les deux. Ensuite, le prochain document ici commence, s’il y en a un. Le format est le suivant:
[n]<
où l'option n représente le numéro du descripteur de fichier. Si le numéro est omis, le document ici fait référence à une entrée standard (descripteur de fichier 0).
Si un caractère quelconque d'un mot est cité, le délimiteur doit être formé en effectuant la suppression de la citation sur le mot, et les lignes du document ici ne doivent pas être développées. Sinon, le délimiteur sera le mot lui-même.
Si aucun mot n'est cité, toutes les lignes du document doivent être développées pour l'extension des parameters, la substitution de commandes et l'extension arithmétique. Dans ce cas, l'entrée dans l'entrée se comporte comme les doubles-guillemets internes (voir Double-guillemets). Cependant, les guillemets ('"') ne doivent pas être traités spécialement dans un document ici, sauf lorsque le guillemet apparaît dans" $ () "," `" "ou" $ {} ".
Si le symbole de redirection est "<< -", tous les caractères
principaux doivent être supprimés des lignes d'entrée et de la ligne contenant le délimiteur final. Si plusieurs opérateurs "<<" ou "<< -" sont spécifiés sur une ligne, le document ici associé au premier opérateur sera fourni en premier par l'application et sera lu en premier par le shell.
Lorsqu'un document est lu depuis un terminal et que le shell est interactif, il doit écrire le contenu de la variable PS2, traitée comme décrit dans les variables shell, à l'erreur standard avant de lire chaque ligne d'entrée jusqu'à ce que le délimiteur ait été reconnu.
Quelques exemples pas encore donnés.
Sans citations:
a=0 cat <
Sortie:
0
Avec des citations:
a=0 cat <<'EOF' $a EOF
ou (moche mais valide):
a=0 cat <
Les sorties:
$a
Sans trait d'union:
cat <a EOF
où
est un onglet littéral et peut être inséré avec Ctrl + V
Sortie:
a
Avec trait d'union:
cat <<-EOF a EOF
Sortie:
a
Cela existe bien sûr pour que vous puissiez indenter votre cat
comme le code environnant, ce qui est plus facile à lire et à maintenir. Par exemple:
if true; then cat <<-EOF a EOF fi
Malheureusement, cela ne fonctionne pas pour les caractères spatiaux: ici, POSIX a favorisé l’indentation des tab
. Oui
Utiliser un tee au lieu d’un chat
Pas exactement comme une réponse à la question initiale, mais je voulais quand même partager ceci: j’avais le besoin de créer un fichier de configuration dans un répertoire nécessitant des droits root.
Ce qui suit ne fonctionne pas pour ce cas:
$ sudo cat </etc/somedir/foo.conf # my config file foo=bar EOF
car la redirection est gérée en dehors du contexte sudo.
J’ai fini par utiliser ceci à la place:
$ sudo tee </dev/null # my config file foo=bar EOF
Ce n’est pas nécessairement une réponse à la question initiale, mais un partage de certains résultats de mes propres tests. Ce:
< print.sh #!/bin/bash echo \$PWD echo $PWD test
produira le même fichier que:
cat < print.sh #!/bin/bash echo \$PWD echo $PWD test
Donc, je ne vois pas l’intérêt d’utiliser la commande cat.