Как избежать замены bash для удаления символа новой строки?

Чтобы ускорить выполнение bash script, я хотел бы сохранить результат команды в переменной с помощью подстановки команд, но подстановка команды заменяет символ 0x0A newline пробелом. Например:

a=`df -H`

или

a=$( df -H )

Когда я хочу продолжить обработку $a, символы новой строки заменяются пробелом, и все строки теперь находятся в одной строке, что намного сложнее grep:

echo $a

Какими были бы легкие трюки, чтобы избежать удаления символа новой строки с помощью подстановки команды?

Ответ 1

Неперехватывающие символы перевода строки не удаляются

Новые строки, которые вы ищете, есть, вы их просто не видите, потому что вы используете echo без цитирования переменной.

Validation

$ a=$( df -H )
$ echo $a
Filesystem Size Used Avail Use% Mounted on /dev/sda3 276G 50G 213G 19% / udev 2.1G 4.1k 2.1G 1% /dev tmpfs 832M 820k 832M 1% /run none 5.3M 0 5.3M 0% /run/lock none 2.1G 320k 2.1G 1% /run/shm
$ echo "$a"
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3       276G   50G  213G  19% /
udev            2.1G  4.1k  2.1G   1% /dev
tmpfs           832M  820k  832M   1% /run
none            5.3M     0  5.3M   0% /run/lock
none            2.1G  320k  2.1G   1% /run/shm
$ 

Удаляются новые символы новой строки

Как правильно указали @user4815162342, хотя новые строки на выходе не удаляются, завершающие новые строки удаляются с заменой команд. См. Эксперимент ниже:

$ a=$'test\n\n'
$ echo "$a"
test


$ b=$(echo "$a")
$ echo "$b"
test
$

В большинстве случаев это не имеет значения, потому что echo добавит удаленную новую строку (если только она не вызывается с опцией -n), но есть некоторые случаи кросс, в которых есть больше, чем одна завершающая строка новой строки на выходе программы, и они почему-то значительны.

Обходные

1. Добавить фиктивный символ

В этом случае, как указано @Scrutinizer, вы можете использовать следующее обходное решение:

$ a=$(printf 'test\n\n'; printf x); a=${a%x}
$ echo "$a"
test


$ 

Объяснение: Символ x добавляется к выводу (используя printf x) после строк новой строки. Поскольку новые строки больше не оканчиваются, они не удаляются подстановкой команд. Следующий шаг - удалить x, который мы добавили, используя оператор % в ${a%x}. Теперь у нас есть исходный результат, со всеми новыми символами!

2. Чтение с использованием замены процесса

Вместо того, чтобы использовать подстановку команд для назначения вывода программы переменной, мы можем вместо этого использовать замещение процесса для подачи вывода программы к встроенной команде read (кредит @ormaaj). Замена процесса сохраняет все новые строки. Чтение вывода в переменную несколько сложно, но вы можете сделать это следующим образом:

$ IFS= read -rd '' var < <( printf 'test\n\n' ) 
$ echo "$var"
test


$ 

Объяснение:

  • Мы устанавливаем внутренний разделитель полей для команды чтения null, с IFS=. В противном случае read не назначил весь вывод var, а только первый токен.
  • Мы вызываем read с параметрами -rd ''. r предназначен для предотвращения обратного слеша, чтобы действовать как специальный символ, а с d '' установить разделитель на ничего, чтобы чтение читало весь вывод, а не только первую строку.

3. Чтение из трубы

Вместо того, чтобы использовать подстановку команд или процессов для назначения вывода программы переменной, мы можем вместо этого передать вывод программы команде read (кредит @ormaaj). Трубопровод также сохраняет все новые строки. Обратите внимание, однако, что на этот раз мы устанавливаем необязательное поведение оболочки lastpipe, используя shopt встроенный. Это необходимо, так что команда read выполняется в текущей среде оболочки. В противном случае переменная будет назначена в подоболочке, и она не будет доступна из остальной части script.

$ cat test.sh 
#!/bin/bash
shopt -s lastpipe
printf "test\n\n" | IFS= read -rd '' var
echo "$var"
$ ./test.sh 
test


$

Ответ 2

Я пытался обвести голову вокруг этого, потому что я использовал bash для потока в результате запуска интерпретатора на F # script. После некоторых проб и ошибок это оказалось для решения проблемы:

$ cat fsi.ch
#!/bin/bash
echo "$(fsharpi --quiet --exec --nologo $1)"

$ fsi.ch messages.fsx
Welcome to my program. Choose from the menu:
new | show | remove

Предполагая, конечно, что вам нужно запустить терминальную программу. Надеюсь, это поможет.