Новая строка в переменных bash


9

Я пытаюсь сохранить несколько строк в переменной bash, но, похоже, это не работает.

Например, если я перечисляю по /binодному файлу в строке и сохраняю его $LS, я передаю $LSкак stdin wc, он всегда возвращает 1:

$ ls -1 /bin | wc -l
134
$ LS=$(ls -1 /bin); wc -l <<< $LS
1

Если я пытаюсь вывести на экран, я получаю различные результаты: echoпечатает все строки в одной строке, а printfпечатает только первую строку:

#!/bin/bash
LS=$(ls -1 /bin)
echo $LS
printf $LS

Итак, переменная bash может содержать несколько строк?

Ответы:


15

Вам нужно заключить его в двойные кавычки (и в большинстве случаев вы должны использовать двойные кавычки ):

echo "$LS"

Но не используйте echo для печати содержимого переменных, вместо этого используйте printf :

printf '%s\n' "$LS"

1
Просто чтобы уточнить общий ответ: printf ожидает, что строка формата будет его первым параметром, поэтому они не увидели того, что ожидали. Если они хотят видеть в выводе команды printf новые строки, произвольно разделенные на пробелы, printf "%s\n" $LSони это сделают.
Джефф Шаллер

% LS должен быть $ LS, кстати (я не мог сделать такое краткое редактирование)
Джефф Шаллер

Спасибо! Это, конечно, работает и с wcдругими командами:wc -l <<< "$LS"
Wizard79

1
@JeffSchaller: Нет, в этом случае вы не должны заключать в кавычки переменные, просто используйте, printf '%s\n' "$LS"если хотите видеть новую строку. Это неправильный набор, исправил это!
Cuonglm

Почему бы вам не использовать echo для печати переменных?
123

9

Новые строки находятся в переменной. LS=$(ls -1)устанавливает переменную LSна выход ls -1(который производит тот же вывод, что и ls, кстати, за исключением случаев, когда выход идет на терминал), минуя завершающие символы новой строки.

Проблема в том, что вы удаляете символы новой строки при распечатывании значения. В сценарии оболочки $LSэто не означает «значение переменной LS», это означает «принять значение LS, разбить его на слова в соответствии IFSи интерпретировать каждое слово как шаблон глобуса». Чтобы получить значение LS, вам нужно написать "$LS"или, в более общем случае, поставить $LSмежду двойными кавычками.

echo "$LS"печатает значение LS, за исключением некоторых оболочек, которые интерпретируют символы обратной косой черты, и за исключением нескольких значений, начинающихся с -.

printf "$LS"печатает значение, LSпока оно не содержит символов процента или обратной косой черты и (с большинством реализаций) не начинается с -.

Чтобы напечатать значение LSточно, используйте printf %s "$LS". Если вы хотите новую строку в конце, используйте printf '%s\n' "$LS".

Обратите внимание, что $(ls)в общем случае это не список файлов в текущем каталоге. Это работает только тогда, когда у вас есть достаточно прирученные имена файлов. Чтобы получить список имен файлов (кроме точечных файлов), необходимо использовать подстановочные: *. Результатом является список строк, а не строка, поэтому вы не можете присвоить ее строковой переменной; Вы можете использовать переменную массива files=(*)в оболочках, которые их поддерживают (ksh93, bash, zsh).

Для получения дополнительной информации см. Почему мой сценарий оболочки задыхается от пробелов или других специальных символов?


printf "$ LS" также поддавался бы разбору символов обратной косой черты, аналогично echo
cnst

0

Вышеупомянутое

printf '%s\n' "$LS"

это единственно правильное решение.

Позвольте мне продемонстрировать, что другие предложенные решения, как с, так echoи printfпросто не работают должным образом:

$ mkdir t
$ cd t
$ touch \\n
$ LS=$(ls -l)
$ echo "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf "$LS\n"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12

$ printf '%s\n' "$LS"
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ ls -l
total 0
-rw-r--r--  1 domain  domain  0 Nov  5 06:12 \n
$ rm \\n
$ cd ..
$ rmdir t
$

(Можно также проверить с V=$(printf 'line0:\\n\\n\nline1.\n') printf '%s\n' "$V"и вариации.)

В то время как \nв именах файлов может быть не так часто, сохранить git diffв переменной, и ваши шансы встретить литерал \nрезко возрастет.


Обратите внимание, что kshи zshподдержка, print -r -- "$LS"а zshтакже имеет echo -E - $LS. cshимеет , echo $LS:qоднако , что не выводит символ новой строки , если $ LS пуста, и получить многострочное значение в $ LS в первую очередь , это довольно сложно в CSH.
Стефан Шазелас
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.