简体   繁体   English

bash 脚本使用双引号、单引号和空格执行命令

[英]bash script execute command with double quotes, single quotes and spaces

I've looked at the similar posts about this problem, but cannot figure out how to get the executed code to be in the correct format, which needs to be foo --bar "a='b'" .我查看了有关此问题的类似帖子,但无法弄清楚如何使执行的代码采用正确的格式,该格式需要为foo --bar "a='b'" My best attempt at this was我最好的尝试是

#!/bin/bash -x

bar='--bar ''"''a='"'"'b'"'"'"'
cmd=(foo $bar)
echo ${cmd[@]}
eval ${cmd[@]}

The output from this is correct for the echo , but incorrect for eval这个输出对于echo是正确的,但对于eval不正确的

+ bar='--bar "a='\''b'\''"'
+ cmd=(foo $bar)
+ echo foo --bar '"a='\''b'\''"'
foo --bar "a='b'"
+ eval foo --bar '"a='\''b'\''"'
++ foo --bar 'a='\''b'\'''

What is the correct way to execute the command with the option?使用选项执行命令的正确方法是什么?

If you must store command fragments, use functions or arrays, not strings.如果您必须存储命令片段,请使用函数或数组,而不是字符串。

An example of best-practice code, in accordance with BashFAQ #50 :根据BashFAQ #50的最佳实践代码示例:

#!/usr/bin/env bash
bar=( --bar a="b" )
cmd=(foo "${bar[@]}" )
printf '%q ' "${cmd[@]}" && echo  # print code equivalent to the command we're about to run
"${cmd[@]}"                       # actually run this code

Bonus: Your debug output doesn't prove what you think it does.奖励:您的调试输出并不能证明您的想法。

"a='b'" and 'a='\\''b'\\''' are two different ways to quote the exact same string . "a='b'"'a='\\''b'\\'''是引用完全相同字符串的两种不同方式。

To prove this:为了证明这一点:

printf '%s\n' "a='b'" | md5sum -
printf '%s\n' 'a='\''b'\''' | md5sum -

...emits as output: ...作为输出发出:

7f183df5823cf51ec42a3d4d913595d7  -
7f183df5823cf51ec42a3d4d913595d7  -

...so there's nothing at all different between how the arguments to echo $foo and eval $foo are being parsed in your code. ...所以在您的代码中解析echo $fooeval $foo的参数之间没有什么不同。

Why is this true?为什么这是真的? Because syntactic quotes aren't part of the command that's actually run;因为句法引号不是实际运行的命令的一部分; they're removed by the shell after it uses them to determine how to interpret a command line character-by-character.在 shell 使用它们来确定如何逐个字符地解释命令行后,它们会被 shell 删除。

So, let's break down what set -x is showing you:那么,让我们分解一下set -x向您展示的内容:

'a='\''b'\'''

...consists of the following literal strings concatenated together: ...由以下连接在一起的文字字符串组成:

  • a= (in a single-quoted context that is entered and ended by the single quotes surrounding) a= (在单引号上下文中,由周围的单引号输入和结束)
  • ' (in an unquoted context, escaped by the backslash that precedes it) ' (在未引用的上下文中,由前面的反斜杠转义)
  • b (in a single-quoted context that is entered and ended by the single quotes surrounding) b (在单引号上下文中,由周围的单引号输入和结束)
  • ' (in an unquoted context) ' (在未引用的上下文中)

...everything else is syntactic , meaningful to the shell but not ever passed to the program foo . ...其他一切都是语法上的,对 shell 有意义,但从未传递给程序foo

If you want exactly the same expansion to happen as in echo ${cmd[@]} , just run the command then:如果您希望发生与echo ${cmd[@]}完全相同的扩展,只需运行以下命令:

${cmd[@]}

It will execute:它将执行:

+ foo --bar '"a='\''b'\''"'

Note that because it is unquoted, for example * will be expanded according to filename expansion .请注意,因为它是未引用的,例如*将根据文件名扩展进行扩展

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM