Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

shell - 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'". 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

+ 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you must store command fragments, use functions or arrays, not strings.

An example of best-practice code, in accordance with 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.

To prove this:

printf '%s
' "a='b'" | md5sum -
printf '%s
' '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.

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.

So, let's break down what set -x is showing you:

'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)
  • ' (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)
  • ' (in an unquoted context)

...everything else is syntactic, meaningful to the shell but not ever passed to the program foo.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...