从 Bash 脚本中的变量调用带有空格的命令行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5730881/
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
Invoking a command line with spaces from a variable in a Bash script
提问by Alain
I thought it would be easy, but I already wasted a few hours on this.
我认为这很容易,但我已经在这上面浪费了几个小时。
I want to run the following CMake command from inside a Bash script. In a terminal I would type
我想从 Bash 脚本中运行以下 CMake 命令。在终端中,我会输入
cmake -G "Unix Makefiles" .
and it works. If I copy this exactly inside the Bash script it works as well.
它有效。如果我将它完全复制到 Bash 脚本中,它也能正常工作。
But the script is meant to work on multiple platforms, and it could be "MSYS Makefiles" instead of "Unix Makefiles". Therefore, I want to put the command in a variable, where the contents depends on the platform and execute it. However, this is where I got stuck. I tried every combination of single/double quotes I could think of, but I got nowhere.
但是该脚本旨在在多个平台上工作,它可以是“MSYS Makefiles”而不是“Unix Makefiles”。因此,我想将命令放在一个变量中,其中内容取决于平台并执行它。然而,这就是我卡住的地方。我尝试了我能想到的所有单/双引号组合,但我一无所获。
I want something along the lines
我想要一些东西
c="cmake . -G \"Unix Makefiles\""
exec $c
but it always results in some variation of the following:
但它总是会导致以下情况的一些变化:
CMake Error: Could not create named generator "Unix
I realize that I could do
我意识到我可以做到
if test [... this is Unix ...]
cmake . -G "Unix Makefiles"
else
cmake . -G "MSYS Makefiles
fi
but since this call has to be made several times I'd rather avoid it.
但是由于必须多次拨打此电话,因此我宁愿避免它。
Any suggestion?
有什么建议吗?
回答by bash-o-logist
It is best not to use evalunnecessarily. Try not to put the command inside a variable.
You can put the options as a variable though:
最好不要eval不必要地使用。尽量不要将命令放在变量中。您可以将选项作为变量:
if [ ... ]
string="Unix makefiles"
else
string="MSYS Makefiles"
else
string="...."
fi
cmake -G "$string" # Just call the command normally
回答by l0b0
The Bash FAQto the rescue: The quotes are syntactical (meaning the quotes are not part of the name), so you should get the expected result with this:
该猛砸FAQ救援:引号是语法(这意味着引号不是名称的一部分),所以你应该得到这个预期的结果:
if test [.... this is Unix ...]
target="Unix Makefiles"
else
target="MSYS Makefiles"
fi
cmake . -G "$target"
PS: evalis evil
PS:eval是邪恶的
回答by John Kugelman
Use evalto tell the shell to parse the command-line anew:
使用eval了告诉shell来重新解析命令行:
c="cmake . -G \"Unix Makefiles\""
eval "$c"
Alternatively, I like using arrays to avoid the unnecessary backslashes and eval:
或者,我喜欢使用数组来避免不必要的反斜杠和eval:
# Store command in 4-element array: ["cmake", ".", "-G", "Unix Makefiles"].
# No backslash escapes needed.
c=(cmake . -G "Unix Makefiles")
# Ugly syntax for expanding out each element of an array, with all the spaces and
# quoting preserved to ensure that "Unix Makefiles" remains a single word.
"${c[@]}"
回答by Blagovest Buyukliev
Calling execon your string, you actually end up executing cmakewith the following arguments:
调用exec您的字符串,您实际上最终cmake使用以下参数执行:
1: .
2: -G
3: "Unix
4: Makefiles"
execitself doesn't interpret quotes, but just spaces, and passes the arguments this way to the execvesystem call. You need to let Bash interpret the quotes by using a built-in like eval.
exec本身不解释引号,而只是解释空格,并以这种方式将参数传递给execve系统调用。您需要让 Bash 使用内置的 like 来解释引号eval。
回答by troffed
You may also use ... | xargs bash -c '...'to reparse a string as command line arguments.
(Using xargsmay, however, not be the ideal solution for multiple platforms.)
您还可以使用... | xargs bash -c '...'将字符串重新解析为命令行参数。(xargs但是,使用可能不是多平台的理想解决方案。)
# Example: find file names with a space
c=". -maxdepth 3 -name \"* *\""
printf '%s' "$c" | xargs bash -c 'set -xv; find "$@"' arg0 2>&1| less
Another option would be to use a shebang helper like shebang.c!
另一种选择是使用像shebang.c这样的 shebang 助手!

