帮助处理变量和新行,以及在 bash 脚本中引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2991276/
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
Help with variables and new lines, and quoting in a bash script
提问by Scott
I would like to automate the following svn command. Note this command produces the desired results on my system - Ubuntu 10.04, svn 1.6.6, bash shell, when issued from the command line:
我想自动化以下 svn 命令。请注意,从命令行发出此命令会在我的系统上产生所需的结果 - Ubuntu 10.04、svn 1.6.6、bash shell:
svn ci -m $'Added new File: newFile.txt\nOrig loc: /etc/networking/newFile.txt' /home/user/svnDir/newFile.txt
I would like to run that command in a bash script, assuming that the original full path to the file is contained in the variable $oFileFull, and the filename is in $oFileName. The script is executed from the svn directory. I need to allow for the possibility that the file name and or path contain spaces.
我想在 bash 脚本中运行该命令,假设文件的原始完整路径包含在变量 $oFileFull 中,并且文件名在 $oFileName 中。该脚本是从 svn 目录执行的。我需要考虑文件名和/或路径包含空格的可能性。
so the line inside my shel script might look like:
所以我的 shell 脚本中的行可能如下所示:
svn ci -m$'Added new file: ${oFileName}\nOrig loc: ${oFileFull}' ${oFileName}
But I want the variables (which may contain spaces) expanded before the command is executed, and I cannot figure out how to do this while enclosing the svn comment in single quotes which is necessary in order to get the new line in the subversion comment log. I am pulling my hair out trying to figure out how to properly quote and assemble this command. Any help appreciated.
但是我希望在执行命令之前扩展变量(可能包含空格),并且在将 svn 注释括在单引号中时我无法弄清楚如何执行此操作,这是在 subversion 注释日志中获取新行所必需的. 我正在努力弄清楚如何正确引用和组合此命令。任何帮助表示赞赏。
回答by Rob Davis
@Scott, I know this has already been answered, but here are some comments on your additional question about the difference between echo $msg and echo "$msg". Your example:
@Scott,我知道这已经得到了回答,但这里有一些关于您关于 echo $msg 和 echo "$msg" 之间区别的附加问题的评论。你的例子:
nl=$'\n'
msg="Line 1${nl}Line 2"
echo $msg # ouput = Line 1 Line 2
echo -e $msg # ouput = Line 1 Line 2
echo "$msg" # output = Line 1
# Line 2
It really helps to know how many arguments the shell is passing to the echo command in each case. Echo takes any number of arguments. It writes all of them to standard output, in order, with a single space after each one except the last one.
了解在每种情况下 shell 传递给 echo 命令的参数数量确实很有帮助。Echo 接受任意数量的参数。它将所有这些按顺序写入标准输出,除了最后一个之外,每个后面都有一个空格。
In the first example, echo $msg, the shell replaces $msg with the characters that you've set it to (one of which is a newline). Then before invoking echoit splits that string into multiple arguments using the Internal Field Separator (IFS), and it passes that resulting list of arguments to echo. By default, the IFS is set to whitespace (spaces, tabs, and newlines), so the shell chops your $msg string into four arguments: "Line", "1", "Line", and "2". Echo never even sees the newline, because the shell considers it a separator, just like a space.
在第一个示例 echo $msg 中,shell 将 $msg 替换为您为其设置的字符(其中一个是换行符)。然后在调用 echo 之前,它使用内部字段分隔符 (IFS) 将该字符串拆分为多个参数,并将生成的参数列表传递给 echo。默认情况下,IFS 设置为空白(空格、制表符和换行符),因此外壳将 $msg 字符串分成四个参数:“Line”、“1”、“Line”和“2”。Echo 甚至从未看到换行符,因为 shell 将其视为分隔符,就像空格一样。
In the second example, echo -e $msg, the echo command receives five arguments: "-e", "Line", "1", "Line", "2". The -e argument tells the command to expand any backslash characters that it sees in its arguments, but there are none, so echo leaves the arguments unchanged. The result is the same as the first example.
在第二个示例中,echo -e $msg,echo 命令接收五个参数:“-e”、“Line”、“1”、“Line”、“2”。-e 参数告诉命令扩展它在其参数中看到的任何反斜杠字符,但没有,因此 echo 保留参数不变。结果与第一个示例相同。
In the last example, echo "$msg", you're telling the shell to expand $msgand pass its contents to echo butto treat everything between the double quotation marks as one argument, so echo receives one argument, a string that contains letters, numbers, spaces and newlines. It echoes that string exactly as it receives it, so "Line 1" and "Line 2" appear on separate lines.
在最后一个示例中,echo "$msg",您告诉 shell 展开$msg并将其内容传递给 echo但将双引号之间的所有内容都视为一个参数,因此 echo 接收一个参数,一个包含字母的字符串,数字、空格和换行符。它与接收到的字符串完全相同,因此“第 1 行”和“第 2 行”出现在不同的行中。
Try this experiment: set the IFS to something arbitrary, like the letter i, and watch how the shell splits your string differently:
试试这个实验:将 IFS 设置为任意值,比如字母 i,然后观察 shell 如何以不同的方式拆分字符串:
nl=$'\n'
msg="Line 1${nl}Line 2"
IFS=i
echo $msg # ouput = L ne 1
# L ne 2
There's nothing especially magical about whitespace. Here, because of the weird IFS, the shell treats the letter i as a separator but not the spaces or newlines. So echo receives three arguments: "L", "ne \nL", and "ne 2". (I'm showing the newline character as \n, but it's really just a single character, like X or p or 5.)
空白没有什么特别神奇的地方。在这里,由于奇怪的 IFS,shell 将字母 i 视为分隔符,而不是空格或换行符。所以 echo 接收三个参数:“L”、“ne \nL”和“ne 2”。(我将换行符显示为 \n,但它实际上只是一个字符,例如 X 或 p 或 5。)
Once you realize that single and double quotation marks on the shell's command line are all about constructing arguments for the commands, the logic begins to make sense.
一旦您意识到 shell 命令行上的单引号和双引号都是关于为命令构造参数,逻辑就开始变得有意义了。
回答by Paused until further notice.
Put your newline in a variable, use the variable wherever you need a newline and change the quotes around your larger string to double quotes. You should also always quote any variable that contains a filename.
将换行符放在变量中,在需要换行符的任何地方使用该变量,并将较大字符串周围的引号更改为双引号。您还应该始终引用包含文件名的任何变量。
nl=$'\n'
svn ci -m"Added new file: ${oFileName}${nl}Orig loc: ${oFileFull}" "${oFileName}"
回答by Scott
@Dennis:
@丹尼斯:
Wow, this is hard to wrap my head around, I'd love it if someone could point me towards an online resource that explains this clearly and concisely. The ones I have found have not cleared it up for me.
哇,这让我难以理解,如果有人能将我指向一个清晰简洁地解释这一点的在线资源,我会很高兴的。我发现的那些并没有为我清除它。
My latest source of confusion is the following:
我最近的困惑来源如下:
#!/bin/bash
nl=$'\n'
msg="Line 1${nl}Line 2"
echo $msg # ouput = Line 1 Line 2
echo -e $msg # ouput = Line 1 Line 2
echo "$msg" # output = Line 1
# Line 2
What I'm attempting to illustrate is that having the double quotes around the variable $msg splits the output into two lines, without the double quotes, even with the -e switch, there is no new line.
我试图说明的是,变量 $msg 周围的双引号将输出分成两行,没有双引号,即使使用 -e 开关,也没有新行。
I don't get why the double quotes are necessary - why isn't the $nl variable expanded when it is assigned as part of the msg variable?
我不明白为什么需要双引号 - 为什么 $nl 变量在被分配为 msg 变量的一部分时没有扩展?
I hope I'm not committing a StackOverflow faux pas by answering my own question. And in fact, I am not really providing an answer, but merely a response to your comment. I cannot format a comment as necessary.
我希望我没有通过回答我自己的问题来犯 StackOverflow 失礼。事实上,我并没有真正提供答案,而只是对您的评论的回应。我无法根据需要格式化评论。
回答by intuited
Bash will concatenate adjacent quoted sections. So for example
Bash 将连接相邻的引用部分。所以例如
$ r=rooty
$ t=tooty
$ echo $r$'\n'$t
rooty
tooty
$ echo "$r $r"$'\n'$t
rooty rooty
tooty
For an online guide, the advanced bash scripting guide may be useful, though it may be no better than just reading bash's long and detailed manual. I recommend using vim's Man command (standard under version 7.2, if not earlier versions) to bring up the bash manual, and then using indent-based folding so that you can browse its heirarchy. Well, assuming that you don't have the time and patience to read all 3300 lines from start to finish.
对于在线指南,高级 bash 脚本指南可能很有用,尽管它可能并不比阅读 bash 长而详细的手册更好。我建议使用 vim 的 Man 命令(7.2 版下的标准命令,如果不是更早的版本)来调出 bash 手册,然后使用基于缩进的折叠,以便您可以浏览其层次结构。好吧,假设您没有时间和耐心从头到尾阅读所有 3300 行。

