Как избежать подстановки команд bash для удаления символа новой строки?
Чтобы ускорить выполнение некоторого bash-скрипта, я хотел бы сохранить результат команды в переменной, используя подстановку команд, но подстановка команд заменяет 0x0A
символ новой строки через пробел. Например:
a=`df -H`
или же
a=$( df -H )
Когда я хочу обработать дальше $a
символы новой строки заменяются пробелом, и все строки теперь находятся на одной строке, что гораздо сложнее:
echo $a
Какими бы простыми приемами можно было избежать удаления символа новой строки при подстановке команды?
2 ответа
Не завершающие переводы строки не удаляются
Новые строки, которые вы ищете, есть, вы просто не видите их, потому что вы используете echo
без кавычек переменной.
Проверка:
$ 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
$
Объяснение:
- Мы устанавливаем внутренний разделитель полей для команды чтения на ноль, с
IFS=
, Иначеread
не назначит весь выводvar
, но только первый токен. - Мы призываем
read
с вариантами-rd ''
,r
для предотвращения обратной косой черты, чтобы действовать как специальный символ, и сd ''
установите разделитель на ничего, чтобы read читал весь вывод, а не только первую строку.
3. Читайте из трубы
Вместо того чтобы использовать подстановку команды или процесса для присвоения выходных данных программы переменной, мы можем вместо этого направить выходные данные программы в read
команда (кредит @ormaaj). Трубопровод также сохраняет все новые строки. Обратите внимание, что на этот раз мы установили lastpipe
необязательное поведение оболочки, используя shopt
встроенный Это необходимо для того, чтобы read
Команда выполняется в текущей среде оболочки. В противном случае переменная будет назначена в подоболочке и не будет доступна из остальной части сценария.
$ cat test.sh
#!/bin/bash
shopt -s lastpipe
printf "test\n\n" | IFS= read -rd '' var
echo "$var"
$ ./test.sh
test
$
Еще один "изящный прием" - использовать символ возврата каретки, который предотвращает удаление новой строки, но ничего не добавляет к выводу:
$ my_func_1 () {
> echo "This newline is squashed"
> }
$ my_func_2 () {
> echo "This newline is not squashed"
> echo -n $'\r'
> }
$ echo -n "$(my_func_1)" && echo -n "$(my_func_2)" && echo done
This newline is squashedThis newline is not squashed
done
$
Но покупатель будьте осторожны: как упоминалось в комментариях, это может хорошо работать для вывода, который просто идет на терминал, но если вы передаете это другому процессу, вы можете запутать его, поскольку он, вероятно, не будет ожидать странного завершения
'\r'
.
Я пытался обернуть голову вокруг этого, потому что я использовал bash для потоковой передачи в результате запуска интерпретатора на скрипте F#. После некоторых проб и ошибок это решило проблему:
$ 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
Предполагая, конечно, что вам нужно запустить терминальную программу. Надеюсь это поможет.