了解如何在命令行中转义字符所需的 bash 提示
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2659777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
bash tips needed for understanding how to escape characters in command-line
提问by Jesper R?nn-Jensen
My knowledge of commandline bash is missing on a particular area: I constantly forget how to properly escape characters. Today I wanted to echo this string into a file:
我在特定领域缺少命令行 bash 的知识:我经常忘记如何正确转义字符。今天我想将这个字符串回显到一个文件中:
#!/bin/env bash
python -m SimpleHTTPServer
However, this fails:
但是,这失败了:
echo "#!/bin/env bash\npython -m SimpleHTTPServer" > server.sh && chmod +x server.sh
-bash: !/bin/env: event not found
That's right: Remember to escape !or bash will think it's a special bash event command.
没错:记住要转义,!否则 bash 会认为这是一个特殊的 bash 事件命令。
But I can't get the escaping right! \!yields \!in the echoed string, and so does \\!.
但我无法正确逃脱!\!收益率\!的呼应字符串中,也是如此\\!。
Furthermore, \nwill not translate to a line break.
此外,\n不会转换为换行符。
Do you have some general tips that makes it easier for me to understand escaping rules?
您是否有一些通用提示可以让我更容易理解转义规则?
To be very precise, I'll accept an answer which tells me which characters I should escape on the bash command line? Including how to correctly output newline and exclamation mark in my example.
准确地说,我会接受一个答案,它告诉我应该在 bash 命令行上转义哪些字符?包括如何在我的示例中正确输出换行符和感叹号。
回答by Chris Johnsen
First, shell quoting is not like C strings. Just because you have a \nbetween quotes does not put a newline in the actual string. It gets a bit confusing sometimes because some versions of echowill interpret the backslash-en combination and output a newline instead. This behavior depends on the exact shell you are using, which options you pass to echo, and which shell options are set, so it is not terribly reliable for cross-platform use. printfis more standardized (it is either a shell builtin or an external program on most systems), but it is not present on (very?) old systems.
首先,shell 引用不像 C 字符串。仅仅因为您有\n引号并不会在实际字符串中放置换行符。有时会有点混乱,因为某些版本echo会解释反斜杠-en 组合并输出换行符。此行为取决于您使用的确切 shell、您传递给的echo选项以及设置的 shell 选项,因此跨平台使用并不是非常可靠。printf更标准化(在大多数系统上它是内置的 shell 或外部程序),但它不存在于(非常?)旧系统上。
As Ignacio Vazquez-Abrams says, single quotes are one answer. The $''variation he mentions at the end are not portable across all shells though (it is not in the POSIX standard for the shell language, and simpler shells do not support it (though ksh, bash, and zshall do)).
正如 Ignacio Vazquez-Abrams 所说,单引号是一种答案。尽管$''他在最后提到的变体不能在所有 shell 中移植(它不在 shell 语言的 POSIX 标准中,并且更简单的 shell 不支持它(尽管ksh、bash和zsh都支持))。
You can even include literal line breaks in a single quoted string:
您甚至可以在单引号字符串中包含文字换行符:
echo '#!/bin/env bash
python -m SimpleHTTPServer' >server.sh &&
chmod +x server.sh
Or, with printf:
或者,使用printf:
printf '#!/bin/env bash\npython -m SimpleHTTPServer\n' >server.sh &&
chmod +x server.sh
You should always take care with the first argument to printfthough, if there are any uspected %characters, they will be interpreted as format specifiers (i.e. you should generally not use unknown strings as the first argument to printf).
您应该始终注意 to 的第一个参数printf,如果有任何可疑%字符,它们将被解释为格式说明符(即您通常不应使用未知字符串作为 的第一个参数printf)。
If you need no interpolation, use single quotes. They let you include literals that include anything except a single quote itself. If you need some C-like escape sequences, either put them in the first argument to printfor use $''(if your shell supports it).
如果不需要插值,请使用单引号。它们允许您包含包含除单引号本身之外的任何内容的文字。如果您需要一些类似 C 的转义序列,请将它们放在 to 的第一个参数中printf或使用$''(如果您的 shell 支持它)。
If you need to include single quotes, you could use double quotes as the outermost quotes, but then you have to worry about what kinds of interpolations happens inside double quotes (varies by shell, but generally, \, $, and `` are all special and` has a special meaning when it is immediately before a newline; !is also special when history expansion is enabled in bash):
如果您需要包括单引号,可以使用双引号作为最外层的引号,但你必须要了解哪类插值的发生双引号内忧(由外壳不同,但通常\,$和`` are all special and`有一个特殊的意思是它紧接在换行符之前;!在bash 中启用历史扩展时也很特殊):
echo "The answer is '$foo'\!"
Or, you could use concatenate multiple single quoted strings with escaped single quotes:
或者,您可以使用转义单引号连接多个单引号字符串:
echo 'The answer is '\''foo'\''!'
Either way, it is not too pretty to think about or read if things get too complex.
无论哪种方式,如果事情变得太复杂,思考或阅读都不太好。
When faced with wanting to include single quotes inside a literal string, you might change to using a quoted‘here document' instead:
当面临想要在文字字符串中包含单引号时,您可能会改为使用带引号的“此处文档”:
cat <<\EOF
The answer is '$foo'!
EOF
The backslash before the EOFmakes the here document a literal one instead of the double-quote-ish one that you get without quoting the terminating word.
之前的反斜杠EOF使 here 文档成为文字文档,而不是您在不引用终止词的情况下获得的双引号文档。
Here documents are easy to output (cat) or to send to other commands as input, but they are not as convenient to use as arguments:
这里的文档很容易输出 ( cat) 或发送到其他命令作为输入,但它们不像参数那样方便使用:
frob -nitz="$(cat <<\EOF
The answer is '$foo'!
EOF
)"
But if you need lots of literal data that includes both single quotes and characters that are special inside double quotes, such a construct can be a huge boon to readability (and writability). Note: as with all other uses of $(), this will eat trailing newlines from the contents of the here document.
但是,如果您需要大量的文字数据,包括单引号和双引号内的特殊字符,那么这样的构造对于可读性(和可写性)来说可能是一个巨大的福音。注意:与 的所有其他用途一样$(),这将占用 here 文档内容中的尾随换行符。
If you need trailing newlines, you can get them, but it is extra work:
如果你需要尾随换行符,你可以得到它们,但这是额外的工作:
s="$(cat <<\EOF
This will have leading and trailing newlines.
It takes as literal everything except a line with only "EOF" on it!$@#&\
(and the "EOF" bit can be changed by using a different word after <<)
The trailing 'xxx' will be trimmed off by the next command.
It is here to protect the otherwise trailing newlines that $() would strip off.
xxx
EOF
)"
s="${s%xxx}"
frob -nitz="$s"
回答by Ignacio Vazquez-Abrams
Single quotes inhibit all escaping and substitution:
单引号禁止所有转义和替换:
echo '$hello world!'
You can alternate or disable quoting if you need to mix things up:
如果您需要混淆,您可以交替或禁用引用:
echo '.00 on '"$horse"'!'
ls -ld ~/'$$'/*
Interpreting escapes is also easy:
解释转义也很容易:
echo $'Wake up!'
sort -n <<< $'4\n3\n8'
回答by user unknown
With -e, bashs buildin echo as well as /bin/echo treat \n as a newline:
使用 -e,bashs buildin echo 以及 /bin/echo 将 \n 视为换行符:
echo -e '#!/bin/env bash\npython -m SimpleHTTPServer'
but I only know -e from echo.
但我只从 echo 中知道 -e。
回答by Paused until further notice.
The easiest way to avoid "event not found" errors is to turn off history expansion:
避免“找不到事件”错误的最简单方法是关闭历史扩展:
set +o histexpand
One thing that hasn't been mentioned yet is that some versions of echosupport the -eoption which causes interpretation of escapes:
尚未提及的一件事是某些版本echo支持-e导致解释转义的选项:
$ echo -e 'two\nlines'
two
lines
回答by yabt
You may also store the newline in a variable:
您还可以将换行符存储在变量中:
NL='
'
printf "%q\n" "${NL}"
sort -n <<< "4${NL}3${NL}8"
# (yet another) example of shell string concatenation
# As a rule of thumb:
# Put anything inside single quotes,
# except "${variables}", "$(commands)" and "'single quotes'".
echo 'The answer is '\''foo'\''!'
echo 'The answer is '"'"'foo'"'"'!' # concatenate 'str1'"str2"...
echo 'The answer is '\
"'"\
'foo'\
"'"\
'!'\
"${NL}`date`"'!'
# ... and sometimes there simply is no need for ${NL} or \n
echo '#!/bin/env bash
python -m SimpleHTTPServer' > server.sh
echo '
line1
line2
line3
' > file

