Как я могу иметь строку в строку в SH?
этой
STR="HellonWorld"
echo $STR
производит как выход
HellonWorld
вместо
Hello
World
что мне делать, чтобы иметь новую строку в строке?
Примечание: этот вопрос не о Эхо.
Я в курсе echo -e
, но я ищу решение, которое позволяет передавать строку (которая включает новую строку) в качестве аргумента другое команды, которые не имеют аналогичной опции для интерпретации n
'S, как новая строка.
10 ответов
решение заключается в использовании $'string'
, например:
$ STR=$'Hello\nWorld'
$ echo "$STR"
Hello
World
вот выдержка из страницы руководства Bash:
Words of the form $'string' are treated specially. The word expands to
string, with backslash-escaped characters replaced as specified by the
ANSI C standard. Backslash escape sequences, if present, are decoded
as follows:
\a alert (bell)
\b backspace
\e
\E an escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\ backslash
\' single quote
\" double quote
\nnn the eight-bit character whose value is the octal value
nnn (one to three digits)
\xHH the eight-bit character whose value is the hexadecimal
value HH (one or two hex digits)
\cx a control-x character
The expanded result is single-quoted, as if the dollar sign had not
been present.
A double-quoted string preceded by a dollar sign ($"string") will cause
the string to be translated according to the current locale. If the
current locale is C or POSIX, the dollar sign is ignored. If the
string is translated and replaced, the replacement is double-quoted.
Echo настолько девяносто и настолько чревато опасностями, что его использование должно привести к дампам ядра не менее 4 ГБ. Серьезно, проблемы echo были причиной того, что процесс стандартизации Unix наконец изобрел printf
утилита, устраняющая все проблемы.
Итак, чтобы получить новую строку в строке:
FOO="hello
world"
BAR=$(printf "hello\nworld\n") # Alternative; note: final newline is deleted
printf '<%s>\n' "$FOO"
printf '<%s>\n' "$BAR"
там! Нет SYSV против BSD Echo madness, все аккуратно печатается и полностью переносится поддержка C escape-последовательностей. Все, пожалуйста, используйте printf
теперь и никогда не оглядываться назад.
то, что я сделал, основываясь на других ответах, было
NEWLINE=$'\n'
my_var="__between eggs and bacon__"
echo "spam${NEWLINE}eggs${my_var}bacon${NEWLINE}knight"
# which outputs:
spam
eggs__between eggs and bacon__bacon
knight
проблема не в оболочке. Проблема на самом деле с echo
сама команда и отсутствие двойных кавычек вокруг переменной интерполяции. Вы можете попробовать использовать echo -e
но это не поддерживается на всех платформах, и одна из причин printf
теперь рекомендуется для переносимости.
вы также можете попробовать вставить новую строку непосредственно в сценарий оболочки (если сценарий-это то, что вы пишете), чтобы он выглядел...
#!/bin/sh
echo "Hello
World"
#EOF
или эквивалентно
#!/bin/sh
string="Hello
World"
echo "$string" # note double quotes!
-
единственная простая альтернатива-фактически ввести новую строку в переменной:
$ STR='new line' $ printf '%s' "$STR" new line
Да, это значит писать Enter где это необходимо в коде.
-
существует несколько эквивалентов
new line
символ.\n ### A common way to represent a new line character. 2 ### Octal value of a new line character. \x0A ### Hexadecimal value of a new line character.
но все они требуют "интерпретации" каким-то инструментом (POSIX printf):
echo -e "new\nline" ### on POSIX echo, `-e` is not required. printf 'new\nline' ### Understood by POSIX printf. printf 'new2line' ### Valid in POSIX printf. printf 'new\x0Aline' printf '%b' 'new12line' ### Valid in POSIX printf.
и поэтому инструмент требуется для сборки строка с новой строкой:
$ STR="$(printf 'new\nline')" $ printf '%s' "$STR" new line
-
в некоторых оболочках последовательность $' является специальным расширением оболочки. Известно, что работает в ksh93, bash и zsh:
$ STR=$'new\nline'
-
конечно, более сложные решения также возможны:
$ echo '6e65770a6c696e650a' | xxd -p -r new line
или
$ echo "new line" | sed 's/ \+/\n/g' new line
найти -e
флаг элегантный и прямо вперед
STR="Hello\nWorld"
echo -e $STR
выходы#
Hello
World
если строка является выходом другой команды, я просто использую кавычки
indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"
Я не эксперт bash, но этот работал для меня:
STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1
$STR2
EOF
)
echo "$NEWSTR"
Я нашел это проще для форматирования текстов.
a $ прямо перед одинарными кавычками '...\северный... однако двойные кавычки не работают.
$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld
в моей системе (Ubuntu 17.10) ваш пример работает по желанию, как при вводе из командной строки (в sh
) и при выполнении как sh
сценарий:
[bash]§ sh
$ STR="Hello\nWorld"
$ echo $STR
Hello
World
$ exit
[bash]§ echo "STR=\"Hello\nWorld\"
> echo $STR" > test-str.sh
[bash]§ cat test-str.sh
STR="Hello\nWorld"
echo $STR
[bash]§ sh test-str.sh
Hello
World
Я думаю, это ответ на ваш вопрос: он просто работает. (Я не пытался выяснить детали, например, в какой именно момент замена символа новой строки на \n
происходит sh
).
однако я заметил, что этот же скрипт будет вести себя по-разному при выполнении С bash
и печать Hello\nWorld
вместо:
[bash]§ bash test-str.sh
Hello\nWorld
мне удалось получить желаемый результат с bash
следующим образом:
[bash]§ STR="Hello
> World"
[bash]§ echo "$STR"
обратите внимание на двойные кавычки $STR
. Это ведет себя одинаково, если сохранено и выполняется как bash
сценарий.
следующее также дает желаемый результат:
[bash]§ echo "Hello
> World"
те придирчивые, которые нуждаются только в новой строке и презирают многострочный код, который ломает отступ, могли бы сделать:
IFS="$(printf '\nx')"
IFS="${IFS%x}"
Bash (и, вероятно, другие оболочки) сожрать все конечные новые строки после замены команды, поэтому вам нужно закончить printf
строка с символом перевода строки и удалить его после этого. Это также может легко стать проявляющаяся.
IFS="$(printf '\nx')" IFS="${IFS%x}"
Я знаю, что это два действия вместо одного, но мой отступ и переносимость ОКР at peace now :) Я изначально разработал это, чтобы иметь возможность разделить вывод только новой строки, и я закончил использование модификации, которая использует
\r
как завершающий символ. Это делает работу разделения новой строки даже для вывода dos, заканчивающегося на\r\n
.IFS="$(printf '\n\r')"