Anche se @cyrus è corretto, in realtà non risponde all'intera domanda e non vi è alcuna spiegazione di ciò che sta accadendo.
Quindi passiamo attraverso di esso.
Newline in stringa
Innanzitutto determinare la sequenza di byte prevista:
$ { echo a; echo b; } | xxd
0000000: 610a 620a a.b.
Ora, usa Sostituzione comandi (Sezione 3.5.4) per tentare di catturare questa sequenza di byte:
$ x=$( echo a; echo b; )
Quindi, fai una semplice eco per verificare la sequenza di byte:
$ echo $x | xxd
0000000: 6120 620a a b.
Quindi sembra che la prima nuova riga sia stata sostituita con uno spazio e la seconda nuova riga sia stata lasciata intatta. Ma perché ?
Vediamo cosa sta realmente accadendo qui:
Innanzitutto, bash eseguirà l' espansione dei parametri della shell (sezione 3.5.3)
Il carattere '$' introduce l'espansione dei parametri, la sostituzione dei comandi o l'espansione aritmetica. Il nome del parametro o il simbolo da espandere può essere racchiuso tra parentesi graffe, che sono opzionali ma servono a proteggere la variabile da espandere dai caratteri immediatamente successivi che possono essere interpretati come parte del nome.
Quindi bash eseguirà la suddivisione in parole (Sezione 3.5.7)
La shell analizza i risultati dell'espansione dei parametri, della sostituzione dei comandi e dell'espansione aritmetica che non si sono verificati tra virgolette doppie per la suddivisione delle parole.
La shell tratta ogni carattere di $ IFS come un delimitatore e divide i risultati delle altre espansioni in parole su questi caratteri. Se IFS non è impostato o il suo valore è esattamente, ...
Successivamente, bash lo tratterà come un semplice comando (Sezione 3.2.1)
Un comando semplice è il tipo di comando che si incontra più spesso. È solo una sequenza di parole separate da spazi, terminate da uno degli operatori di controllo della shell (vedi Definizioni). La prima parola generalmente specifica un comando da eseguire, con il resto delle parole come argomenti di quel comando.
La definizione di spazi vuoti (Sezione 2 - Definizioni)
vuoto Uno spazio o un carattere di tabulazione.
Infine, bash invoca il comando interno echo (Sezione 4.2 - Comandi incorporati di Bash)
... Emette gli arg, separati da spazi, terminati con una nuova riga. ...
Quindi, per riassumere, le nuove righe vengono rimosse da Word Splitting, quindi echo ottiene 2 arg, "a" e "b", e quindi li emette separati da spazi e termina con una nuova riga.
Seguendo le indicazioni di @cyrus (e sopprimendo la nuova riga da echo con -n) il risultato è migliore:
$ echo -n "$x" | xxd
0000000: 610a 62 a.b
Newline alla fine della stringa
Tuttavia, non è ancora perfetto, la nuova riga finale è scomparsa. Osservando più da vicino la sostituzione dei comandi (sezione 3.5.4) :
Bash esegue l'espansione eseguendo il comando e sostituendo la sostituzione del comando con l'output standard del comando, eliminando tutte le nuove righe finali.
Ora che è chiaro perché la newline scompare, bash può essere ingannato nel mantenerlo. Per fare ciò, aggiungi una stringa aggiuntiva alla fine e rimuovila quando usi la variabile:
$ x=$( echo a; echo b; echo -n extra )
$ echo -n "${x%extra}" | xxd
0000000: 610a 620a a.b.
TL; DR
Aggiungi parte extra alla fine dell'output e cita le variabili:
$ 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