How can I have a newline in a string in sh?
这个
1 2 3 | STR="Hello World" echo $STR |
作为输出生成
1 2 | Hello World |
而不是
1 2 | Hello World |
如果字符串中有换行符,我该怎么做?
注意:这个问题与echo无关。我知道
解决方案是使用
1 2 3 4 5 | $ STR=$'Hello World' $ echo"$STR" Hello World |
以下是bash手册页面的摘录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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 new line carriage return \t horizontal tab \v vertical tab \\ backslash \' single quote " double quote nn 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是如此的90年代,充满了危险,以至于它的使用会导致核心转储不少于4GB。说真的,echo的问题是Unix标准化过程最终发明了
所以要在字符串中获取换行符:
1 2 3 4 5 6 7 8 9 | FOO="hello world" BAR=$(printf"hello world ") # Alternative; note: final newline is deleted printf '<%s> '"$FOO" printf '<%s> '"$BAR" |
那里!没有SysV和BSD的回声疯狂,一切得到整洁的打印和完全可移植的C转义序列支持。现在请大家使用
我根据其他答案所做的是
1 2 3 4 5 6 7 8 9 | NEWLINE=$' ' 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 |
问题不在外壳上。问题实际上在于
您还可以尝试将换行符直接插入shell脚本(如果您正在编写的是脚本),这样看起来…
1 2 3 4 | #!/bin/sh echo"Hello World" #EOF |
或等价地
1 2 3 4 | #!/bin/sh string="Hello World" echo"$string" # note double quotes! |
唯一简单的选择是在变量中实际键入新行:
1 2 3 4 5 | $ STR='new line' $ printf '%s'"$STR" new line |
是的,这意味着在代码中需要的地方编写enter。
有几个等同于
1 2 3 | ### 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)的"解释":
1 2 3 4 5 6 7 | echo -e"new line" ### on POSIX echo, `-e` is not required. printf 'new line' ### Understood by POSIX printf. printf 'new\012line' ### Valid in POSIX printf. printf 'new\x0Aline' printf '%b' 'new\0012line' ### Valid in POSIX printf. |
因此,需要使用该工具构建一个带有新行的字符串:
1 2 3 4 5 | $ STR="$(printf 'new line')" $ printf '%s'"$STR" new line |
在某些shell中,序列$'是一个特殊的shell扩展。已知在KSH93、Bash和Zsh工作:
1 2 | $ STR=$'new line' |
当然,更复杂的解决方案也是可能的:
1 2 3 | $ echo '6e65770a6c696e650a' | xxd -p -r new line |
或
1 2 3 4 | $ echo"new line" | sed 's/ \+/ /g' new line |
我觉得江户十一〔六〕旗优雅而笔直。
1 2 3 4 5 6 | bash$ STR="Hello World" bash$ echo -e $STR Hello World |
如果字符串是另一个命令的输出,我只使用引号
1 2 | indexes_diff=$(git diff index.yaml) echo"$indexes_diff" |
A$位于单引号"……"之前,如下所示,但是双引号不起作用。
1 2 3 4 5 6 7 8 | $ echo $'Hello World' Hello World $ echo $"Hello World" Hello World |
我不是bash专家,但这个对我很有用:
1 2 3 4 5 6 7 8 9 | STR1="Hello" STR2="World" NEWSTR=$(cat << EOF $STR1 $STR2 EOF ) echo"$NEWSTR" |
我发现这样更容易格式化文本。
我对这里的任何选择都不太满意。这就是我的工作。
1 2 3 4 5 | str=$(printf"%s""first line") str=$(printf"$str %s""another line") str=$(printf"$str %s""and another line") |
那些挑剔的人只需要换行,轻视破坏缩进的多行代码,可以做到:
1 2 3 | IFS="$(printf ' x')" IFS="${IFS%x}" |
bash(以及可能的其他shell)在命令替换之后吞掉所有尾随的换行符,因此需要用非换行符结束
1 2 | IFS="$(printf ' x')" IFS="${IFS%x}" |
I know this is two actions instead of one, but my indentation and portability OCD is at peace now :) I originally developed this to be able to split newline-only separated output and I ended up using a modification that uses
as the terminating character. That makes the newline splitting work even for the dos output ending with
.
1
2
3 IFS="$(printf '
')"
在我的系统(Ubuntu 17.10)上,无论是从命令行(输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [bash]§ sh $ STR="Hello World" $ echo $STR Hello World $ exit [bash]§ echo"STR="Hello World" > echo \$STR"> test-str.sh [bash]§ cat test-str.sh STR="Hello World" echo $STR [bash]§ sh test-str.sh Hello World |
我想这回答了你的问题:它只是起作用。(我还没有试图弄清楚细节,比如在什么时候,在
但是,我注意到,在使用
World
1 2 3 | [bash]§ bash test-str.sh Hello World |
我已经设法用
1 2 3 | [bash]§ STR="Hello > World" [bash]§ echo"$STR" |
注意
下面还提供了所需的输出:
1 2 | [bash]§ echo"Hello > World" |