Как добавить новые строки в переменные в скрипте bash


64

Когда я делаю

str="Hello World\n===========\n"

Я \nтоже распечатал. Как я могу иметь переводы строки тогда?


1
Хотя ответы здесь отличные, в действительности я думаю, что вам лучше использовать массив для подобных вещей большую часть времени.
evilsoup

Ответы:


73

В bashвы можете использовать синтаксис

str=$'Hello World\n===========\n'

Одинарные кавычки, $начинающиеся с символа a, - это новый синтаксис, который позволяет вставлять escape-последовательности в строки.

Также printfвстроенная функция позволяет сохранить полученный результат в переменную

printf -v str 'Hello World\n===========\n'

Оба решения не требуют подоболочки.

Если в следующем вам нужно напечатать строку, вы должны использовать двойные кавычки, как в следующем примере:

echo "$str"

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


1
Как называется синтаксис str=$'Hello World\n===========\n'? подстановка переменных?
Зенг

5
@zengr: это называется цитированием ANSI-C , а также поддерживается в zshи ksh; однако, это НЕ POSIX-совместимый.
mklement0

4
@ mkelement0, взятый из ksh93, также поддерживается zsh, bash, mksh и FreeBSD sh, и обсуждается вопрос о
Стефан Шазелас

1
Кажется, не работает с двойными кавычками? например str=$"My $PET eats:\n$PET food"? Этот подход работает для двойных кавычек
Брэд Паркс

31

Вы можете поместить буквальные символы новой строки в одинарные кавычки (в любой оболочке в стиле Bourne / POSIX).

str='Hello World
===========
'

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

mycommand <<'EOF'
Hello World
===========
EOF

Если вы хотите сохранить строку в переменной, используйте catкоманду в подстановке команд. Символы новой строки в конце строки будут удалены командой замены. Если вы хотите сохранить последние символы новой строки, поставьте стопор в конце и затем удалите его. В POSIX-совместимых оболочках вы можете писать с str=$(cat <<'EOF'); str=${str%a}последующим указанием собственно heredoc, но bash требует, чтобы heredoc появлялся перед закрывающей скобкой.

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}

В ksh, bash и zsh вы можете использовать $'…'форму в кавычках, чтобы расширить экранирование обратной косой черты внутри кавычек.

str=$'Hello World\n===========\n'

1
Я использую GNU bash 4.1.5, и str=$(cat <<'EOF')не работает как есть .. )Необходимо поместить на следующую строку после конца документа EOF... но даже в этом случае он теряет завершающий символ новой строки из-за Command Замена.
Peter.O

@fred Хорошие моменты, я объяснил о конце новой строки и показал код, который работает в bash. Я думаю, что это ошибка в bash, хотя, если честно, перечитывая спецификацию POSIX, я нахожу неясным, что такое поведение является обязательным, когда << находится внутри подстановки команд, а heredoc - нет.
Жиль "ТАК - перестань быть злым"

Отличный материал; чтобы сохранить конечные (и ведущие) \nэкземпляры bashпри захвате here-документа в переменной, рассмотрите IFS= read -r -d '' str <<'EOF'...в качестве альтернативы подходу с ограничителем (см. мой ответ).
mklement0

8

Вы используете "эхо"? Попробуйте "эхо-е".

echo -e "Hello World\n===========\n"

2
КСТАТИ. Вам не нужен последний \ n, потому что он echoбудет добавлен автоматически, если вы не укажете -n. (Однако главный вопрос в том, как получить эти переводы строк в переменную).
Peter.O

+1 Из всех решений это самое прямое и простое.
Хай Ву

echo -e не работает в OS X
Грег М. Крсак

2
@GregKrsak: В bash, echo -e делает работу на OS X - это потому , что echoэто Баш встроенный (а не внешний исполняемый файл) и встроенной поддержки делает -e. ( В качестве встроенной команды, он должен работать на всех платформах , которые Баш бежит на, кстати, echo -eработает kshи zshтоже). Напротив, однако, внешняя echoутилита на OS X /bin/echo- действительно не поддерживает -e.
mklement0

4

Если вам много раз нужны новые строки в вашем скрипте, вы можете объявить глобальную переменную, содержащую новую строку. Таким образом, вы можете использовать его в строках в двойных кавычках (расширения переменных).

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"

Зачем $''нужна подоболочка?
Мат

Извините, я неправильно прочитал ответ.
pihentagy

Могу ли я попросить объяснений у downvoters?
pihentagy

Приятно! Это может быть включено в переменные с использованием двойных кавычек, например"My dog eats:${NL}dog food"
Брэд Паркс

Это сработало для меня. При использовании сценария bash для компоновки строки, которая автоматически копируется в буфер обмена для последующего вставки в другом месте, этот подход работал для добавления новых строк в результирующий вывод.
Вилле

3

Из всего обсуждения вот самый простой способ для меня:

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========

Команда echo должна использовать двойные кавычки .


3

Чтобы дополнить великие существующие ответы:

Если вы используете bashи предпочитаете использовать фактические символы новой строки для удобства чтения , readэто еще один вариант для захвата документа here в переменной , который (как и другие решения здесь) не требует использования подоболочки.

# Reads a here-doc, trimming leading and trailing whitespace.
# Use `IFS= read ...` to preserve it (the trailing \n, here).
read -r -d '' str <<'EOF'   # Use `IFS= read ...` to preserve the trailing \n
Hello World
===========
EOF
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
  • -rгарантирует, что readне будет интерпретировать ввод (по умолчанию, он будет обрабатывать обратную косую черту специальным образом, но это редко требуется).

  • -d ''устанавливает разделитель «запись» в пустую строку, заставляя readчитать весь ввод сразу (вместо одной строки).

Обратите внимание, что, оставив $IFS(внутренний разделитель полей) по умолчанию $' \t\n'(пробел, табуляцию, символ новой строки), любой начальный и конечный пробел обрезается по значению, назначенному для него $str, включая конечный символ новой строки здесь-документа.
(Обратите внимание , что даже если тело здесь-Дока начинается на линию после старта разделителя ( 'EOF'здесь), он не содержит ведущую строку).

Как правило, это желаемое поведение, но если вы хотите использовать этот завершающий символ новой строки, используйте IFS= read -r -d ''вместо «просто» read -r -d '', но учтите, что все начальные и конечные пробелы сохраняются.
(Обратите внимание, что добавление IFS= непосредственно к readкоманде означает, что назначение действует только во время этой команды, поэтому нет необходимости восстанавливать предыдущее значение.)


Использование here-doc также позволяет при желании использовать отступ для выделения многострочной строки для удобства чтения:

# Caveat: indentation must be actual *tab* characters - spaces won't work.
read -r -d '' str <<-'EOF' # NOTE: Only works if the indentation uses actual tab (\t) chars.
    Hello World
    ===========
EOF
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]

Помещение -между <<и открывающим разделителем here-doc ( 'EOF', здесь) приводит к удалению начальных символов табуляции из тела here-doc и даже к закрывающему разделителю, но обратите внимание, что это работает только с фактическими символами табуляции , а не пробелами, так что если ваш Редактор переводит нажатия клавиш табуляции в пробелы, требуется дополнительная работа.


-1

вам нужно сделать это так:

STR=$(echo -ne "Hello World\n===========\n")

Обновить:

Как указал Фред, таким образом вы потеряете завершающий "\ n". Чтобы назначить переменную с расширенными последовательностями обратной косой черты, выполните:

STR=$'Hello World\n===========\n\n'

давайте проверим это:

echo "[[$STR]]"

дает нам сейчас:

[[Hello World
===========

]]

Обратите внимание, что $ '' отличается от $ "". Второй делает перевод в соответствии с текущей локалью. Для получения более подробной информации см. Раздел ЦИТИРОВАНИЕ в man bash.


-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

result+=$(printf '%s' "$foo")$'\n'
result+=$(printf '%s' "$bar")$'\n'

echo "$result"
printf '%s' "$result"

выход:

FOO
BAR

FOO
BAR

1
Почему не просто result+=$foo$'\n'? $(printf %s "$foo")будет обрезать завершающие символы новой строки, $fooесли таковые имеются.
Стефан Шазелас

Нет никакого объяснения для кода, иначе он выглядит хорошо для меня.
что-то
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.