Як додати нові рядки до змінних у скрипті bash


64

Коли я це роблю

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

Я отримую \nнадруковані теж. Як я можу мати нові рядки тоді?


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

Відповіді:


73

У bashви можете використовувати синтаксис

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

Одиночні лапки, що передує a, $- це новий синтаксис, який дозволяє вставляти послідовності втечі.

Також printfвбудований дозволяє зберегти отриманий результат на змінну

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

Обидва рішення не потребують передплати.

Якщо в наступному вам потрібно роздрукувати рядок, ви повинні використовувати подвійні лапки, як у наступному прикладі:

echo "$str"

тому що, коли ви друкуєте рядок без лапок, новий рядок перетворюється на пробіли.


1
Як називається синтаксис str=$'Hello World\n===========\n'? змінна підміна?
zengr

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

4
@ mkelement0, він походить від ksh93, також підтримується zsh, bash, mksh та FreeBSD sh, і його включення до наступної великої редакції POSIX обговорюється
Stéphane Chazelas

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}подальшим відповідним гередоком, але bash вимагає, щоб гередок з'явився перед дужками, що закриваються.

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 Заміна.
Пітер.О

@fred Хороші моменти, я пояснив, що стосується останніх рядків та показав код, який працює в bash. Я думаю, що це помилка в bash, хоча, якщо чесно, при перечитуванні специфікації POSIX, мені здається, незрозуміло, що поведінка призначена, коли << знаходиться всередині заміни команд, а heredoc - ні.
Жиль

Чудові речі; щоб зберегти відстежуючі (і провідні) \nекземпляри bashпри захопленні here-doc у змінній, розглянемо 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. (Як вбудований, він повинен працювати на всіх платформах, на яких працює bash; до речі, echo -eпрацює kshі в zsh). Навпаки, зовнішня echoутиліта OS X - /bin/echo- дійсно не підтримує -e.
mklement0

3

Якщо вам потрібні нові рядки у вашому сценарії багато разів, ви можете оголосити глобальну змінну, що містить новий рядок. Таким чином, ви можете використовувати його в рядках з подвійним котируванням (змінними розширеннями).

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

Навіщо $''вимагати передплату?
Мат

Вибачте, я неправильно прочитав відповідь.
pihentagy

Чи можу я попросити пояснення у поточних людей?
pihentagy

Приємно! Це може бути включено до змінних, використовуючи подвійні лапки, наприклад"My dog eats:${NL}dog food"
Brad Parks,

3

З усіх обговорень, ось для мене найпростіший спосіб:

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

Команда echo повинна використовувати подвійні лапки .


3

Щоб доповнити чудові відповіді:

Якщо ви використовуєте, bashі ви вважаєте за краще використовувати фактичні нові рядки для читабельності , readє ще одним варіантом захоплення тут-док в змінну , яка (як і інші рішення тут) не вимагає використання підзаголовка.

# 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, що включає в себе зворотний новий рядок тут-doc.
(Зауважте, що незважаючи на те, що тіло here-doc починається на лінії після розмежувача старту ( 'EOF'тут), воно не містить провідного нового рядка).

Зазвичай, це бажана поведінка, але якщо ви хочете, щоб цей трейлінг нового рядка був використаний, IFS= read -r -d ''а не просто read -r -d '', але зауважте, що будь-яка провідна та відстала пробіли зберігається.
(Зауважте, що попереднє додавання IFS= безпосередньо до readкоманди означає, що присвоєння діє лише під час цієї команди, тому не потрібно відновлювати попереднє значення.)


Використання тут-документа також дозволяє необов'язково використовувати відступ, щоб відкласти багаторядковий рядок для читабельності:

# 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
===========]

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


-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.