Присваивание не удаляет символы новой строки, это фактически echoделает это. Вам нужно просто заключить строку в кавычки, чтобы сохранить эти символы новой строки:
echo "$testvar"
Это даст желаемый результат. См. Следующую стенограмму демонстрации:
pax> cat num1.txt ; x=$(cat num1.txt)
line 1
line 2
pax> echo $x ; echo '===' ; echo "$x"
line 1 line 2
===
line 1
line 2
Причина , почему новые строки заменяются пробелами не полностью делать с echoкомандой, а это сочетание вещей.
Когда задана командная строка, bashразбивает ее на слова в соответствии с документацией для IFSпеременной:
IFS: Внутренний разделитель полей, который используется для разделения слов после раскрытия ... значение по умолчанию <space><tab><newline>.
Это означает, что по умолчанию любой из этих трех символов может использоваться для разделения вашей команды на отдельные слова. После этого разделители слов исчезли, все, что у вас осталось, это список слов.
Объедините это с echoдокументацией ( bashвнутренняя команда), и вы поймете, почему выводятся пробелы:
echo [-neE] [arg ...]: вывести аргументы, разделенные пробелами, за которыми следует новая строка .
Когда вы используете echo "$x", он заставляет всю xпеременную быть одним словом в соответствии с bash, следовательно, она не разбивается. Вы можете увидеть это с помощью:
pax> function count {
...> echo $#
...> }
pax> count 1 2 3
3
pax> count a b c d
4
pax> count $x
4
pax> count "$x"
1
Здесь countфункция просто выводит количество заданных аргументов. 1 2 3И a b c dварианты показать его в действии.
Затем мы пробуем это с двумя вариантами xпеременной. Один без кавычек показывают , что есть четыре слова, "test", "1", "test"и "2". Добавление кавычек делает его одним словом "test 1\ntest 2".