Comment sortir une chaîne multiligne dans Bash?

250

Comment puis-je sortir une chaîne multipline dans Bash sans utiliser plusieurs appels d'écho comme ceci:

echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo 
echo "Report bugs to: "
echo "up home page: "

Je suis à la recherche d'un moyen portable de le faire, en utilisant uniquement les modules internes Bash.

méthode d'aide
la source
4
Si vous émettez un message d'utilisation en réponse à une invocation incorrecte, vous enverriez normalement ce message à l'erreur standard au lieu de la sortie standard, avececho >&2 ...
Mark Reed
2
@MarkReed Le message d'utilisation est sorti en tapant --help(qui devrait aller à la sortie standard).
helpermethod
Pour ceux qui viennent, plus d'informations sur "ici les documents" sont disponibles: tldp.org/LDP/abs/html/here-docs.html
Jeffrey Martinez
Vérifiez la printfsolution basée sur Gordon Davidson. Bien qu'il soit dans l'ombre des approches echoou catbasées, il semble être beaucoup moins compliqué. Certes, la syntaxe `printf 'représente un peu une courbe d'apprentissage, mais j'aimerais
entendre
Connexe: stackoverflow.com/questions/23929235/…
Anton Tarasenko

Réponses:

296

Ici, les documents sont souvent utilisés à cette fin.

cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page:
EOF

Ils sont pris en charge dans tous les shells dérivés de Bourne, y compris toutes les versions de Bash.

En pause jusqu'à nouvel ordre.
la source
4
Ouais - mais ce catn'est pas intégré.
Mark Reed
8
@MarkReed: C'est vrai, mais il est toujours disponible (sauf éventuellement dans des circonstances inhabituelles).
pause jusqu'à nouvel ordre.
6
+1 Thx. J'ai fini par utiliser read -d '' help <<- EOF ...pour lire la chaîne multiligne dans une variable, puis j'ai fait écho au résultat.
helpermethod
3
puis-je enregistrer un HEREDOC dans une variable?
chovy
177

ou vous pouvez le faire:

echo "usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page: "
Chris Mohr
la source
1
@OliverWeiler: Cela fonctionnera même dans les shells Bourne tels que Dash et Heirloom Bourne Shell .
pause jusqu'à nouvel ordre.
6
Pas génial si vous en avez besoin dans une fonction, car vous devrez soit 1) dépasser la chaîne complètement à gauche de votre fichier ou 2) le garder en retrait pour s'aligner avec le reste de votre code, mais il imprime avec les retraits aussi
sg
43

Inspiré par les réponses perspicaces de cette page, j'ai créé une approche mixte, que je considère comme la plus simple et la plus flexible. Qu'est-ce que tu penses?

Tout d'abord, je définis l'utilisation dans une variable, ce qui me permet de la réutiliser dans différents contextes. Le format est très simple, presque WYSIWYG, sans avoir besoin d'ajouter de caractères de contrôle. Cela me semble raisonnablement portable (je l'ai exécuté sur MacOS et Ubuntu)

__usage="
Usage: $(basename $0) [OPTIONS]

Options:
  -l, --level <n>              Something something something level
  -n, --nnnnn <levels>         Something something something n
  -h, --help                   Something something something help
  -v, --version                Something something something version
"

Ensuite, je peux simplement l'utiliser comme

echo "$__usage"

ou encore mieux, lors de l'analyse des paramètres, je peux simplement y faire écho dans une ligne:

levelN=${2:?"--level: n is required!""${__usage}"}
Jorge
la source
4
cela a fonctionné pour moi dans un script où la réponse ci-dessus ne fonctionne pas (sans modification).
David Welch
3
C'est beaucoup plus propre que d'impliquer un tas de caractères comme \ t et \ n qui sont difficiles à trouver dans le texte et à développer pour rendre la sortie très différente de la chaîne dans le script
sg
1
Pour certaines raisons, il imprime tout sur la même ligne pour moi: /
Nicolas de Fontenay
2
@Nicolas: L'utilisation de guillemets doubles echo "$__usage"était nécessaire pour moi. echo $__usagen'a pas marché.
Mario
24

Utilisez l' -eoption, puis vous pouvez imprimer un nouveau caractère de ligne avec \ndans la chaîne.

Échantillon (mais je ne sais pas s'il est bon ou non)

Ce qui est amusant, c'est que cette -eoption n'est pas documentée dans la page de manuel de MacOS alors qu'elle est toujours utilisable. Il est documenté dans la page de manuel de Linux .

nhahtdh
la source
6
Ces pages de manuel sont destinées à la echocommande fournie par le système /bin/echo, qui sur Mac OS n'a pas d' -eoption. lorsque vous utilisez bash sur ces systèmes, sa echocommande intégrée prend le relais. Vous pouvez le voir en tapant explicitement /bin/echo whateveret en observant la différence de comportement. Pour voir la documentation du intégré, tapez help echo.
Mark Reed
1
/bin/echoest souvent différent d'un OS à l'autre et différent de la fonction intégrée de Bash echo.
pause jusqu'à nouvel ordre.
@MarkReed: J'essaierai plus tard, mais merci pour l'info. +1. Je vais laisser ma réponse ici, car il y a beaucoup de bonnes discussions en cours.
nhahtdh
7
echo -en'est pas portable - par exemple, certaines implémentations d'écho afficheront le "-e" dans le cadre de la sortie. Si vous souhaitez la portabilité, utilisez plutôt printf. Par exemple, / bin / echo sur OS X 10.7.4 fait cela. L'écho intégré de l'IIRC était également bizarre sous 10.5.0, mais je ne me souviens plus des détails.
Gordon Davisson
2
echo -em'a mordu avant ... Certainement utiliser printfou catavec un hérédoc. La <<-variante de la documentation ici est particulièrement agréable car vous pouvez supprimer l'indentation principale dans la sortie, mais le retrait pour la lisibilité dans le script
zbeekman
22

Comme je l'ai recommandé printfdans un commentaire, je devrais probablement donner quelques exemples de son utilisation (bien que pour imprimer un message d'utilisation, je serais plus susceptible d'utiliser les réponses de Dennis ou Chris). printfest un peu plus complexe à utiliser que echo. Son premier argument est une chaîne de format, dans laquelle les échappements (comme \n) sont toujours interprétés; il peut également contenir des directives de format commençant par %, qui contrôlent où et comment tous les arguments supplémentaires y sont inclus. Voici deux approches différentes pour l'utiliser pour un message d'utilisation:

Tout d'abord, vous pouvez inclure l'intégralité du message dans la chaîne de format:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"

Notez que contrairement à echo, vous devez inclure explicitement la nouvelle ligne finale. De plus, si le message contient des %caractères, ils doivent être écrits sous la forme %%. Si vous souhaitez inclure les adresses de rapport de bug et de page d'accueil, vous pouvez les ajouter tout naturellement:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: %s\nup home page: %s\n" "$bugreport" "$homepage"

Deuxièmement, vous pouvez simplement utiliser la chaîne de format pour lui faire imprimer chaque argument supplémentaire sur une ligne distincte:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: " "up home page: "

Avec cette option, l'ajout des adresses de rapport de bogue et de page d'accueil est assez évident:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"
Gordon Davisson
la source
9

De plus, avec le code source en retrait, vous pouvez utiliser <<-(avec un tiret de fin) pour ignorer les tabulations en tête (mais pas les espaces en tête). Par exemple ceci:

if [ some test ]; then
    cat <<- xx
        line1
        line2
xx
fi

Génère du texte en retrait sans le premier espace blanc:

line1
line2
Vue elliptique
la source
Cela n'a pas fonctionné pour moi. Quel shell utilisez-vous?
four43
N'a pas fonctionné dans bash 4.4.19 dans Ubuntu. Il n'a pas supprimé l'espacement avant la ligne 1 et la ligne 2
four43
1
@ four43, vous aviez raison. Ne fonctionne pas pour supprimer les espaces de début. Cependant, supprime les onglets de tête. J'ai donc corrigé ma réponse des tabulations et des espaces, aux tabulations et non aux espaces. Désolé pour l'erreur. J'ai vérifié le manuel et il indique clairement que les onglets sont supprimés. Merci d'avoir porté cela à mon attention.
Vue elliptique le
0

Si vous utilisez la solution de @jorge et constatez que tout est sur la même ligne, assurez-vous de placer la variable entre guillemets:

echo $__usage

imprimera tout sur une seule ligne alors que

echo "$__usage"

conservera les nouvelles lignes.

user1165471
la source
C'est en fait la seule solution qui a fonctionné pour moi. Printf fait beaucoup de choses et avec mon XML multiligne, il nécessite probablement beaucoup d'échappements car il gâche complètement le contenu. J'attribue foo = cat <<EOF .... EOF&& echo "$ foo"
Jilles van Gurp