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。
目前似乎有效的是插入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[@]}"
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)
没有单引号——这只是当您使用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)
但是,你几乎可以肯定要传递--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}")
Run Code Online (Sandbox Code Playgroud)
然后
mkvpropedit file.mkv "${MYSETTINGS[@]}"
Run Code Online (Sandbox Code Playgroud)
请注意,变量扩展周围不需要额外的双引号,因为双引号"${name[@]}"将 的每个元素扩展name为一个单独的单词,而无需进一步标记化 - 进一步的引号\"name=${TITLE_NAME}\"将按字面传递给命令。
另请参阅我们如何运行存储在变量中的命令?
| 归档时间: |
|
| 查看次数: |
51 次 |
| 最近记录: |