Answers:
解决方案是使用$'string'
,例如:
$ STR=$'Hello\nWorld'
$ echo "$STR" # quotes are required here!
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.
STR=$"Hello\nWorld"
只需prints即可Hello\nWorld
。
H="Hello"; W="World"; STR="${H}"$'\n'"${W}"; echo "${STR}"
将在单独的行上回显“ Hello”和“ World”
Echo已经九十年代了,充满了危险,以至于使用它会导致核心转储不少于4GB。严重的是,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 vs BSD的回音疯狂,所有内容都被整齐地打印,并且完全支持C换码序列。大家请printf
现在就使用,永远不要回头。
$'string'
更加干净。
$'foo'
自2013年起,该语法是无效的POSIX语法。许多shell都会抱怨。
BAR=$(printf "hello\nworld\n")
不为我打印尾随\ n
$()
由POSIX指定为在替换结束时删除一个或多个<newline>字符的序列。
我发现-e
国旗优雅而直截了当
bash$ STR="Hello\nWorld"
bash$ echo -e $STR
Hello
World
如果字符串是另一个命令的输出,我只用引号
indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"
echo
。
echo -e
因其可移植性问题而臭名昭著。与POSIX之前相比,这现在不像狂野西部那样,但是仍然没有理由喜欢echo -e
。另请参阅stackoverflow.com/questions/11530203/…–
唯一简单的选择是在变量中实际键入新行:
$ STR='new
line'
$ printf '%s' "$STR"
new
line
是的,这意味着Enter在代码中需要的地方编写。
一个new line
字符有几个等效项。
\n ### A common way to represent a new line character.
\012 ### 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 'new\012line' ### Valid in POSIX printf.
printf 'new\x0Aline'
printf '%b' 'new\0012line' ### Valid in POSIX printf.
因此,该工具需要用换行符生成字符串:
$ STR="$(printf 'new\nline')"
$ printf '%s' "$STR"
new
line
在某些shell中,序列$'是特殊的shell扩展。已知可在ksh93,bash和zsh中工作:
$ STR=$'new\nline'
当然,也可以使用更复杂的解决方案:
$ echo '6e65770a6c696e650a' | xxd -p -r
new
line
要么
$ echo "new line" | sed 's/ \+/\n/g'
new
line
在我的系统(Ubuntu 17.10)上,无论从命令行(toto)键入还是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(可能还有其他shell)会在命令替换后吞噬所有尾随的换行符,因此您需要以printf
非换行符结尾该字符串,然后再将其删除。这也很容易成为一体。
IFS="$(printf '\nx')" IFS="${IFS%x}"
我知道这是两个动作,而不是一个,但我的缩进和可移植性OCD现在处于和平状态:)我最初开发此功能是为了能够拆分仅换行符分隔的输出,并且最终使用了
\r
用作终止字符的修改。即使对于以结尾的dos输出,这也使换行拆分工作\r\n
。IFS="$(printf '\n\r')"
我对这里的任何选项都不是很满意。这对我有用。
str=$(printf "%s" "first line")
str=$(printf "$str\n%s" "another line")
str=$(printf "$str\n%s" "and another line")
str=$(printf '%s\n' "first line" "another line" "and another line")
(shell将方便地(或不方便地)从命令替换中修剪所有最后的换行符)。这里的几种答案已经printf
以各种形式推广,因此我不确定这是否可以作为单独的答案增加任何价值。
printf '%s\n' "first line" \
(换行,缩进)'second line'
等。另请参见有关printf -v str
在不产生子shell的情况下分配变量的信息。