从 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:49:57  来源:igfitidea点击:

Invoking a command line with spaces from a variable in a Bash script

bash

提问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 助手!