Bash 的 eval、变量和引号问题
我一直在这里和其他地方阅读有关 bash 中的引号的内容,但我没有得到解决这个问题的帮助。
问题是,我有一个用于循环备份的小脚本。
如果我不使用eval
,那么我就会遇到rsync
中的$OPTIONS
变量的问题。
但如果我确实使用 eval
那么问题就出在变量 $CURRENT_DIR
...
rsync 返回以下消息:“意外的本地参数:/path/with”
I”已经尝试了引用变量 $CURRENT_DIR
的各种方法
CURRENT_DIR="/path/with spaces/backup"
DIR="dir_by_project"
f=":/home/project_in_server"
OPTIONS="-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete"
eval rsync --delete-excluded -i $OPTIONS [email protected]$f $CURRENT_DIR/xxx/$DIR/files
,有什么方法可以使用变量 $CURRENT_DIR
而不会出现空格引起的问题?
I've been reading about quotes in bash here and everywhere else, but i got no help solving this problem.
The thing is, I have a little script for doing backups in a loop.
If I don't use eval
then I have problems with $OPTIONS
variable in rsync
.
But if I do use eval
then the problem goes to the variable $CURRENT_DIR
...
rsync returns the following message: 'Unexpected local arg: /path/with'
I've tried every way of quoting the variable $CURRENT_DIR
CURRENT_DIR="/path/with spaces/backup"
DIR="dir_by_project"
f=":/home/project_in_server"
OPTIONS="-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete"
eval rsync --delete-excluded -i $OPTIONS [email protected]$f $CURRENT_DIR/xxx/$DIR/files
Is there any way that i can use the variable $CURRENT_DIR
without problems caused by spaces?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
command "some thing"
使用一个参数some thing
执行命令。引号由 shell 解析,参数在执行命令时设置为数组。该命令将把参数视为不带引号的某些东西。eval 命令对待它的参数或多或少就像它们被输入到 shell 中一样。因此,如果您
eval命令“some thing”
,bash会使用两个参数执行eval
:command
和some thing
(当 bash 设置参数数组时,引号再次被吃掉)。因此,eval 的行为就好像您在 shell 中输入了命令某些内容
,这不是您想要的。我所做的只是转义引号,以便 bash 从字面上传递“一些东西”,包括 eval 的引号。然后,eval 的行为就像您键入
命令“some thing”
。我的命令中的外部引号并不是严格要求的,它们只是习惯。你也可以使用:
command "some thing"
executes command with one argumentsome thing
. The quotes are parsed by the shell and arguments are setup as an array when executing the command. The command will see an argument as some thing without the quotes.The eval command treats its arguments more or less as if they were typed into the shell. So, if you
eval command "some thing"
, bash executeseval
with two arguments:command
andsome thing
(again the quotes are eaten while bash sets up the array of arguments). So, eval then acts as if you typedcommand some thing
in the shell, which is not what you want.What I did was simply to escape the quotes, so that bash passes literally "some thing" including the quotes to eval. eval then acts as if you typed
command "some thing"
.The outer quotes in my command is not strictly required, they're just habit. You could just as well use:
使用 eval 是危险的,应尽可能避免。在这种情况下,主要问题是您试图将 OPTIONS 定义为包含多个单词,而 bash 变量不能很好地处理这个问题。有一个解决方案:将 OPTIONS 放入数组中,而不是简单的变量中(并在所有变量引用周围使用双引号,以防止空格被视为单词分隔符)。
Using eval is dangerous, and should be avoided whenever possible. In this case, the primary problem is that you're trying to define OPTIONS as containing multiple words, and bash variables don't handle this very well. There is a solution: put OPTIONS in an array, instead of a simple variable (and use double-quotes around all variable references, to keep spaces from getting treated as word separators).
BASH 常见问题解答条目 #50:“我试图将命令放入变量中,但复杂的情况总是失败!”
BASH FAQ entry #50: "I'm trying to put a command in a variable, but the complex cases always fail!"
通用可重用解决方案
虽然了解如何正确引用事物很重要,但为了易于使用并防止出现失误,我更喜欢使用函数:
以下通过引用数组的每个元素来保留参数中的空格:
示例用法:< /strong>
在上面,请注意
单个标记
的空格被引用为\
。这表明令牌确实是分开的。
给定一些不受信任的用户输入:
构造一个评估命令:
使用看似正确的引用来评估它:
请注意,您已被黑客攻击。
date
被执行而不是按字面打印。相反,使用
token_quote()
:eval
并不是邪恶的 - 它只是被误解了:)Generic reusable solution
While understanding how to correctly quote things is important, for ease of use and to prevent slip-ups I prefer to use a function:
The following keeps spaces in arguments by quoting each element of array:
Example usage:
Above, note the
single token
's space is quoted as\
.This shows that the tokens are indeed kept separate.
Given some untrusted user input:
Construct a command to eval:
Eval it, with seemingly correct quoting:
Note you were hacked.
date
was executed rather than being printed literally.Instead with
token_quote()
:eval
isn't evil - it's just misunderstood :)我同意戈登的观点,
在这种情况下,您不需要 eval (您不是从变量形成变量名,或者以其他方式动态创建表达式)
并且您想要双引号所有可能包含空格的变量引用想要保留
但是另一个好习惯是始终使用 {} ...
而不是
引用变量这可以消除任何名称歧义
I agree with Gordon
You have no need for eval in this case (you are not forming a variable name from variables, or otherwise making an expression on the fly)
And and you want to double-quote all variable referensces that COULD have spaces that you would want to preserve
But Another good habit is to always refrence variables with {} ...
instead of
This removes any name ambiguity
我知道您可能已经使用过它,但是单引号怎么样? (这种类型'')?
I know probably you have used it already, but, what about single quotes? (this type ' ' ) ?
您需要在
CURRENT_DIR="/path/with\spaces/backup"
中转义空格,如果这不起作用,则添加双反斜杠CURRENT_DIR="/path/with\\spaces/backup ”
You need to escape space in
CURRENT_DIR="/path/with\ spaces/backup"
if this doesn't work then put double backslashCURRENT_DIR="/path/with\\ spaces/backup"