如何将带引号的多字字符串替换为参数?

Posted

技术标签:

【中文标题】如何将带引号的多字字符串替换为参数?【英文标题】:How to substitute quoted, multi-word strings as arguments? 【发布时间】:2012-03-18 01:37:44 【问题描述】:

我正在尝试将包含多个引号的字符串变量替换为命令的参数。

因此,给定以下示例脚本(注意 shebang 中的 -x,它会导致输出记录到 stderr),

#!/bin/bash -x

myArg="\"hello\" \"world\""
echo "string is:" $myArg

exit

这给了我们,

+ myArg='"hello" "world"'
+ echo 'string is:' '"hello"' '"world"'
string is: "hello" "world"
+ exit

第二行显示了实际传递给命令的内容; bash 为字符串中的每个单词添加了单引号。因此,如果我改为引用“$myArg”,则会发生相同的情况,但针对整个字符串而不是每个单词。

现在,假设我们将字符串传递给程序,而不是echo,其中一些参数需要被引用模式,例如"*"(不能被shell扩展)。

为了澄清,我不希望在扩展过程中添加单引号。我怎样才能做到这一点?

【问题讨论】:

你在做什么?除非你对eval 做一些讨厌的事情,否则传递给程序的字符串是否包含"*"* 应该无关紧要。 致任何困惑的人:注意 shebang 中的 -x,它会导致输出被记录。 @Pumbaa80,确实,我已在问题中添加了该说明。 与:***.com/questions/17338863/…一起有用 【参考方案1】:

如果您想将变量值作为参数传递(SO 上 99% 的情况),只需使用正确的quoting:

arg="foo bar"
command "$arg"

如果要传递多个参数,请使用数组:

args=("foo bar" "baz ban" bay)
command "$args[@]"

【讨论】:

正如@gordon-davisson 所澄清的那样,数组确实是答案,非常感谢!【参考方案2】:

不要使用引号,使用数组(参见BashFAQ #050):

$ myArgs=("hello" "world" "multiword arg with * ?")
+ myArgs=("hello" "world" "multiword arg with * ?")
$ echo "$myArgs[@]"
+ echo hello world 'multiword arg with * ?'
hello world multiword arg with * ?

如果它真的需要在字符串中以带引号的字符串的形式出现,你要么必须使用eval "echo $myArg" 之类的东西(如果你不小心,这可能会导致一些非常讨厌的错误)或自己解析(这会很困难)。

【讨论】:

这种数组方法非常有效,非常感谢!附言。来自子 shell 的任何打印操作都由父 shell 解释,因此任何这样的“eval”语句似乎都给出了同样的坏结果。【参考方案3】:

我不认为它正在做你认为它正在做的事情。

[~]$ myArg="\"hello\" \"world\""
[~]$ echo "string is:" $myArg
string is: "hello" "world"

我没有看到任何额外的引号 - echo 得到三个参数字符串。

[~]$ cargs() echo $#; 
[~]$ cargs "string is:" $myArg
3

bash会先展开变量,所以

cargs "string is:" $myArg

变成(虽然没有文字反斜杠 - 这就是为什么字符串转义是 PITA)

cargs "string is:" "\"hello\"" "\"world\""

而args数组是:

0x00:string is:0
0x0B:"hello"0
0x13:"world"0
0x1B:0

现在,如果您在其中一个中添加 * 或 glob 路径扩展,Bash 将在此时扩展它,除非您对其进行转义,或在文字命令中使用单引号。

[~]$ cargs "string is:" $myArg *
19
[~]$ cargs "string is:" $myArg "\*"
4
[~]$ cargs "string is:" $myArg '*'
4

【讨论】:

Echo 的 output 确实完美地打印了引用的单词,但是传递给 echo 的输入参数(如问题中调试输出的第二行所示)是单引号 -双引号('"str"'),不幸的是,这对于我正在使用的工具来说是毫无意义的输入。【参考方案4】:

有一种可移植的方式来拆分扩展变量但保留空格。不需要 Bash 数组。 Dash(Ubuntu 的 /bin/sh)也可以。

使用一些字符来分隔参数中绝对没有使用的参数。下面的示例使用分号,但它可以是换行符或其他字符。当参数列表展开时,将IFS 变量临时更改为换行符。尽快将IFS 恢复到原始值,即使这意味着在循环中执行。如果不能保证循环至少运行一次,也可以在循环之后执行。

#! /bin/sh
arg_list='hello world;have a nice day'
save_IFS="$IFS"
IFS=';'
for i in $arg_list; do
  IFS="$save_IFS"
  echo "$i"
done
IFS="$save_IFS"

请注意,每个扩展参数都是单独打印的。

$ ./test.sh
hello world
have a nice day

【讨论】:

以上是关于如何将带引号的多字字符串替换为参数?的主要内容,如果未能解决你的问题,请参考以下文章

shell中,如何替换双引号中内容为某个变量?

怎么将带特殊字符的字符串存入sqlserver的某个字段

如何替换不在引号中的字符串

《web前端笔记7》js字符—获取、查找、遍历、提取、替换方法总结

如何在java中用\替换字符串中的“(双引号)”

如何将带单引号的字符串转换为双引号以进行 json 解析