我有一个脚本,我可以在其中动态更改必须传递给命令的参数(mkv属性编辑器在这种情况下)。考虑下面的示例脚本:
#!/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[@]}
当我运行这个时,我进入控制台:
[~] # ./test.sh
Count = 2
+ mkvpropedit --edit 1 --set '"language=eng' 'lish"'
但我想最终调用时没有单引号mkv属性编辑器,像这样:
+ mkvpropedit --edit 1 --set "language=eng lish"
我也尝试将数组回显到变量中,并且 echo 删除了单引号,但随后我无法使用该变量作为mkv属性编辑器因为单引号又出现了...
当然,如果变量是单个单词,例如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[@]}
如果我运行这个脚本,我会得到(由于错误的引用):
# ./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"').
如果我手动运行:
# mkvpropedit file.mkv --edit track:2 --set "name=my title"
The file is being analyzed.
The changes are written to the file.
Done.
所以这绝对是一个引用问题;我想调用mkv属性编辑器在脚本中使用数组。
使用评估
目前看来有效的是将mkvpropedit
和file.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[@]}"
返回:
# ./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.
答案1
没有单引号- 当您使用 时,这只是 shell 对变量内容的明确表示set -x
。您可以看到,如果您使用declare -p
或一次打印一个数组元素来查看数组元素:
LANG_NAME="eng lish"
MYSETTINGS=()
MYSETTINGS+=("--edit 1")
MYSETTINGS+=("--set \"language=${LANG_NAME}\"")
然后
$ declare -p MYSETTINGS
declare -a MYSETTINGS=([0]="--edit 1" [1]="--set \"language=eng lish\"")
或者
$ printf '>>>%s<<<\n' "${MYSETTINGS[@]}"
>>>--edit 1<<<
>>>--set "language=eng lish"<<<
然而,您几乎肯定希望将--edit
、1
、--set
、 和language=eng lish
作为单独的标记传递给命令,这意味着
在数组构造期间引用包含空格或全局字符的每个标记,例如
language="${LANG_NAME}"
或"language=${LANG_NAME}"
使用数组扩展时双引号(以防止分词和文件名生成 - 又名“split+glob”)
所以
LANG_NAME="eng lish"
MYSETTINGS=()
MYSETTINGS+=(--edit 1)
MYSETTINGS+=(--set language="${LANG_NAME}")
然后
mkvpropedit file.mkv "${MYSETTINGS[@]}"
请注意,您不需要在变量扩展周围添加额外的双引号,因为双引号"${name[@]}"
会将 的每个元素扩展name
为单独的单词,而无需进一步标记化 - 进一步的引号\"name=${TITLE_NAME}\"
将按字面意思传递给命令。
也可以看看我们如何运行存储在变量中的命令?
答案2
[错误的] 转义美元符号:
MYSETTINGS+=("--set name=\${TITLE_NAME}")
或者:
MYSETTINGS+=('--set name=${TITLE_NAME}')
mkvpropedit file.mkv ${MYSETTINGS[@]}
用于执行命令时要扩展的变量
./test.sh
+ mkvpropedit file.mkv --edit track:2 --set 'name=${TITLE_NAME}'
The file is being analyzed.
The changes are written to the file.
Done.