Même si @cyrus est correct, cela ne répond pas réellement à toute la question et il n’explique aucune explication de ce qui se passe.
Alors laisse marcher à travers elle.
Newlines dans la chaîne
Déterminez d’abord la séquence d’octets attendue:
$ { echo a; echo b; } | xxd
0000000: 610a 620a a.b.
Maintenant, utilisez Commande de substitution (Section 3.5.4) pour tenter de capturer cette séquence d'octets:
$ x=$( echo a; echo b; )
Ensuite, faites un simple écho pour vérifier la séquence d'octets:
$ echo $x | xxd
0000000: 6120 620a a b.
Il semble donc que la première nouvelle ligne a été remplacée par un espace et que la deuxième nouvelle ligne est restée intacte. Mais pourquoi ?
Regardons ce qui se passe réellement ici:
Premièrement, bash fera l’ extension des paramètres de shell (Section 3.5.3)
Le caractère '$' introduit le développement de paramètres, la substitution de commandes ou le développement arithmétique. Le nom du paramètre ou le symbole à développer peut être placé entre accolades, qui sont facultatifs mais servent à protéger la variable à développer des caractères qui le suivent immédiatement, qui pourraient être interprétés comme faisant partie du nom.
Ensuite, bash fera le fractionnement de mots (Section 3.5.7)
Le shell analyse les résultats du développement des paramètres, de la substitution de commande et du développement arithmétique qui ne se sont pas produits entre guillemets doubles pour le fractionnement des mots.
Le shell traite chaque caractère de $ IFS comme un séparateur et divise les résultats des autres extensions en mots sur ces caractères. Si IFS n'est pas défini, ou si sa valeur est exactement, ...
Ensuite, bash le traitera comme une commande simple (Section 3.2.1)
Une commande simple est le type de commande le plus souvent rencontré. C'est juste une séquence de mots séparés par des blancs, terminés par l'un des opérateurs de contrôle du shell (voir Définitions). Le premier mot spécifie généralement une commande à exécuter, le reste des mots étant les arguments de cette commande.
La définition des blancs (Section 2 - Définitions)
blank Espace ou tabulation.
Enfin, bash appelle la commande interne echo (Section 4.2 - Commandes intégrées de Bash)
... Affiche les arguments, séparés par des espaces, terminés par une nouvelle ligne. ...
Donc, pour résumer, les nouvelles lignes sont supprimées par Word Splitting, puis echo obtient 2 arguments, "a" et "b", puis les génère séparés par des espaces et se terminant par une nouvelle ligne.
En faisant ce que @cyrus a suggéré (et supprimez la nouvelle ligne de echo avec -n), le résultat est meilleur:
$ echo -n "$x" | xxd
0000000: 610a 62 a.b
Newlines à la fin de la chaîne
Ce n'est toujours pas parfait, la fin de ligne est partie. Regarder de plus près la substitution de commande (Section 3.5.4) :
Bash exécute le développement en exécutant commande et en remplaçant la substitution de commande par la sortie standard de la commande, avec tout retour à la ligne final supprimé.
Maintenant que la raison pour laquelle la nouvelle ligne disparaît est claire, bash peut être trompé pour la conserver. Pour ce faire, ajoutez une chaîne supplémentaire à la fin et supprimez-la lorsque vous utilisez la variable:
$ x=$( echo a; echo b; echo -n extra )
$ echo -n "${x%extra}" | xxd
0000000: 610a 620a a.b.
TL; DR
Ajoutez une partie supplémentaire à la fin de la sortie et des variables de citation:
$ cat /no/file/here 2>&1 | xxd
0000000: 6361 743a 202f 6e6f 2f66 696c 652f 6865 cat: /no/file/he
0000010: 7265 3a20 4e6f 2073 7563 6820 6669 6c65 re: No such file
0000020: 206f 7220 6469 7265 6374 6f72 790a or directory.
$ cat /no/file/here 2>&1 | cksum
3561909523 46
$
$ var=$( cat /no/file/here 2>&1; rc=${?}; echo extra; exit ${rc})
$ echo $?
1
$
$ echo -n "${var%extra}" | xxd
0000000: 6361 743a 202f 6e6f 2f66 696c 652f 6865 cat: /no/file/he
0000010: 7265 3a20 4e6f 2073 7563 6820 6669 6c65 re: No such file
0000020: 206f 7220 6469 7265 6374 6f72 790a or directory.
$ echo -n "${var%extra}" | cksum
3561909523 46