从数组中的双引号变量元素中删除单引号并运行命令

vir*_*ldj 2 bash shell-script quoting

我有一个脚本,我可以在其中动态更改必须传递给命令的参数(在本例中为mkvpropedit)。考虑下面的示例脚本:

#!/bin/bash

LANG_NAME="eng lish"

MYSETTINGS=()
MYSETTINGS+=("--edit 1")
MYSETTINGS+=("--set \"language=${LANG_NAME}\"")

echo "Count = ${#MYSETTINGS[@]}" # should be 2
set -x # enable to see the invoked command
mkvpropedit ${MYSETTINGS[@]}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我进入控制台:

[~] # ./test.sh
Count = 2
+ mkvpropedit --edit 1 --set '"language=eng' 'lish"'
Run Code Online (Sandbox Code Playgroud)

我不希望mkvpropedit的最终调用中使用单引号,如下所示:

+ mkvpropedit --edit 1 --set "language=eng lish"
Run Code Online (Sandbox Code Playgroud)

我还尝试将数组回显到变量中,并且 echo 删除了单引号,但是我无法将该变量用作mkvpropedit的参数,因为单引号再次出现...

当然,如果变量是单个单词,例如LANG_NAME="eng". 我的 Bash 版本是 3.2(实际上是 Busybox)。

更新的问题

可能下面的例子更好地解释了我想要做什么。我已经更改了一些名称以使其可复制。

#!/bin/bash

TITLE_NAME="my title"

MYSETTINGS=()
MYSETTINGS+=("--edit track:2")
MYSETTINGS+=("--set \"name=${TITLE_NAME}\"")

set -x
mkvpropedit file.mkv ${MYSETTINGS[@]} 
Run Code Online (Sandbox Code Playgroud)

如果我运行这个脚本,我得到(由于错误的引用):

# ./test.sh
+ mkvpropedit file.mkv --edit track:2 --set '"name=my' 'title"'
Error: More than one file name has been given ('file.mkv' and 'title"').
Run Code Online (Sandbox Code Playgroud)

而如果我运行,手动:

# mkvpropedit file.mkv --edit track:2 --set "name=my title"
The file is being analyzed.
The changes are written to the file.
Done.
Run Code Online (Sandbox Code Playgroud)

所以这绝对是一个引用问题;我想使用脚本中的数组调用mkvpropedit

使用评估

目前似乎有效的是插入mkvpropeditfile.mkv插入数组并最终调用eval "${MYSETTINGS[@]}",但这是否值得且安全?不是eval 邪恶(双关语)吗?

TITLE_NAME="my title"

MYSETTINGS=(mkvpropedit file.mkv)
MYSETTINGS+=("--edit track:2")
MYSETTINGS+=("--set \"name=${TITLE_NAME}\"")

set -x
eval "${MYSETTINGS[@]}"
Run Code Online (Sandbox Code Playgroud)

返回:

# ./test.sh
+ eval mkvpropedit file.mkv '--edit track:2' '--set "name=my title"'
++ mkvpropedit file.mkv --edit track:2 --set 'name=my title'
The file is being analyzed.
The changes are written to the file.
Done.
Run Code Online (Sandbox Code Playgroud)

ste*_*ver 5

没有单引号——这只是当您使用set -x. 您可以看到,如果您改为使用declare -p或一次打印一个来查看数组元素:

LANG_NAME="eng lish"

MYSETTINGS=()
MYSETTINGS+=("--edit 1")
MYSETTINGS+=("--set \"language=${LANG_NAME}\"")
Run Code Online (Sandbox Code Playgroud)

然后

$ declare -p MYSETTINGS
declare -a MYSETTINGS=([0]="--edit 1" [1]="--set \"language=eng lish\"")
Run Code Online (Sandbox Code Playgroud)

或者

$ printf '>>>%s<<<\n' "${MYSETTINGS[@]}"
>>>--edit 1<<<
>>>--set "language=eng lish"<<<
Run Code Online (Sandbox Code Playgroud)

但是,你几乎可以肯定要传递--edit1--set,并language=eng lish作为单独的令牌的命令,表示

  1. 在数组构造期间引用包含空格或全局字符的每个标记,例如language="${LANG_NAME}""language=${LANG_NAME}"

  2. 使用时双引号引用数组扩展(以防止分词和文件名生成 - 又名“split+glob”)

所以

LANG_NAME="eng lish"

MYSETTINGS=()
MYSETTINGS+=(--edit 1)
MYSETTINGS+=(--set language="${LANG_NAME}")
Run Code Online (Sandbox Code Playgroud)

然后

mkvpropedit file.mkv "${MYSETTINGS[@]}"
Run Code Online (Sandbox Code Playgroud)

请注意,变量扩展周围不需要额外的双引号,因为双引号"${name[@]}"将 的每个元素扩展name为一个单独的单词,而无需进一步标记化 - 进一步的引号\"name=${TITLE_NAME}\"将按字面传递给命令。

另请参阅我们如何运行存储在变量中的命令?


归档时间:

查看次数:

51 次

最近记录:

4 年,8 月 前