Pourquoi bash supprime \ n dans $ (fichier cat)?

24

Si j'ai le fichier input.txtcontenant:

hello
world
!

Ensuite, l'exécution de la commande bash echo $(cat input.txt)produira ceci:

hello world !

Pourquoi et comment puis-je le corriger pour afficher exactement ce qui se trouve dans le fichier, comment il se trouve dans le fichier?

f.ardelian
la source

Réponses:

32

Si tu utilises

echo "$(cat input.txt)"

cela fonctionnera correctement.

L'entrée d'écho est probablement séparée par des retours à la ligne, et elle le traitera comme des commandes distinctes, donc le résultat sera sans retour à la ligne.

arian
la source
Agréable! Alors, quelle est la différence (le cas échéant) entre $ () et backticks? (Désolé si c'est trop tangentiel)
Chan-Ho Suh
Ils sont équivalents, sauf que $ (...) est plus facile à imbriquer. Dans les deux cas, si vous ne citez pas le résultat, il sera symbolisé en plusieurs arguments sur un espace blanc.
James Henstridge
3
Mais le dernier caractère de nouvelle ligne est omis, même entre guillemets. En revanche, l'opérateur de backtick de Perl s'étend à la sortie entière de la commande, y compris tous les retours à la ligne.
Keith Thompson
6
@KeithThompson yes, la substitution de commandes supprime tous les retours à la ligne de fin de la sortie. Cela a par exemple l'avantage de echo "$(date) something"supprimer la nouvelle ligne de fin de la sortie de la date, ce qui fait que l'écho affiche la date et "quelque chose" sur la même ligne. Si vous devez stocker un fichier ou une sortie de commande "en l'état", utilisez mapfile ( help mapfile) read -rd ''ou une boucle de lecture while.
geirha
Merci à tous :-) J'ai appris quelque chose de chaque commentaire ici!
Chan-Ho Suh
2

Extrait de la page de manuel de bash, section Command Substitution:

Les sauts de ligne incorporés ne sont pas supprimés, mais ils peuvent être supprimés lors du fractionnement des mots.

Un peu plus loin, même section:

Si la substitution apparaît entre guillemets, le fractionnement des mots et l'expansion des noms de chemin ne sont pas effectués sur les résultats.

Voilà pourquoi ça echo "$(cat /etc/passwd)" marche.

De plus, il faut savoir que la substitution de commandes par les spécifications POSIX supprime les sauts de ligne de fin:

$ echo "$(printf "one\ntwo\n\n\n")"
one
two

Ainsi, la sortie d'un fichier via $(cat file.txt)peut entraîner la perte de sauts de ligne, et cela peut être un problème si l'intégrité du fichier entier est prioritaire.

Sergiy Kolodyazhnyy
la source
2

Vous pouvez conserver les retours à la ligne, par exemple en définissant IFS sur vide:

$ IFS=
$ a=$(cat links.txt)
$ echo "$a"
link1
link2
link3
Sarnath Jegadeesan
la source