809 votes

Comment fonctionne "cat << EOF" dans bash?

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é que la syntaxe suivante fonctionne :

cat << EOF | psql ---params
BEGIN;

`pg_dump ----something`

update table .... statement ...;

END;
EOF

Cela construit correctement la chaîne multi-ligne (de BEGIN; à END;, inclusivement) et la passe en tant qu'entrée à psql.

Mais je n'ai aucune idée de comment/pourquoi cela fonctionne, quelqu'un pourrait-il s'il vous plaît expliquer?

Je fais principalement référence à cat << EOF, je sais que > écrit dans un fichier, >> ajoute à un fichier, < lit une entrée depuis un fichier.

Que fait exactement <<?

Et y a-t-il une page de manuel à ce sujet?

34 votes

C'est probablement une utilisation inutile de cat. Essayez psql ... << EOF ... Voir aussi "here strings". mywiki.wooledge.org/BashGuide/InputAndOutput?#Here_Strings

1 votes

Je suis surpris que cela fonctionne avec cat mais pas avec echo. cat devrait s'attendre à un nom de fichier en tant que stdin, pas une chaîne de caractères. psql << EOF semble logique, mais pas autrement. Fonctionne avec cat mais pas avec echo. Comportement étrange. Une idée à ce sujet ?

0 votes

En me répondant : chat sans paramètres exécute et réplique en sortie tout ce qui est envoyé via l'entrée (stdin), utilisant ainsi sa sortie pour remplir le fichier via >. En fait, un nom de fichier lu comme un paramètre n'est pas un flux stdin.

0voto

YordanGeorgiev Points 1222

Il convient de noter que les doc ici fonctionnent également dans les boucles bash. Cet exemple montre comment obtenir la liste des colonnes de la table:

export postgres_db_name='my_db'
export table_name='my_table_name'

# start copy 
while read -r c; do test -z "$c" || echo $table_name.$c , ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}"
SELECT column_name
FROM information_schema.columns
WHERE 1=1
AND table_schema = 'public'
AND table_name =:'table_name' ;
EOF
)
# stop copy , now paste straight into the bash shell ...

output: 
my_table_name.guid ,
my_table_name.id ,
my_table_name.level ,
my_table_name.seq ,

ou même sans le saut de ligne

while read -r c; do test -z "$c" || echo $table_name.$c , | perl -ne 
's/\n//gm;print' ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}"
 SELECT column_name
 FROM information_schema.columns
 WHERE 1=1
 AND table_schema = 'public'
 AND table_name =:'table_name' ;
 EOF
 )

 # output: daily_issues.guid ,daily_issues.id ,daily_issues.level ,daily_issues.seq ,daily_issues.prio ,daily_issues.weight ,daily_issues.status ,daily_issues.category ,daily_issues.name ,daily_issues.description ,daily_issues.type ,daily_issues.owner

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X