编辑:
进一步阅读之前的重要说明:自从Kusalananda 的 anwser以来,我的问题现在已经毫无用处了,因为他指出了我使用的另一个脚本中的错误。现在这个bug被修复了,我描述的下面的错误不再发生了!
您的代码中有两个问题导致 $extension 中的值被扩展
第二个问题是函数本身
TL;博士
当我开始写这个问题时,我被卡住了,但找到了一个可行的解决方案(使用shell noglob),但我仍然有一个“是否可以写”的问题。
我确信这已经得到解答,但是我迷失在数百个关于 bash 扩展的主题中。
这是我的情况:
- 我想运行一个脚本(可以说带有接受正则表达式
ffmpeg
的选项模式)-pattern_type glob -i
*.JPG
- 争论(假设
*.JPG
) - 来自变量的参数(比如说
$extension
) - 来自脚本参数的变量(比如说
$1
) - 但我不希望 shell
$extension
默认扩展为像这样的模式*.JPG
请注意,所有这些操作都发生在脚本script.sh
中。
因此,用户可以运行:
script.sh 'JPG' ; # where $1='JPG'
注意:在 中script.sh
,我连接*.
并$1
获得更最终的正则表达式,例如*.JPG
我读到(从这里https://stackoverflow.com/a/11456496/912046)外壳扩展发生在ffmpeg
接收参数之前(ffmpeg
甚至不知道外壳扩展发生)
我尝试以不同的方式使用引号、双引号或反斜杠${extension}
,但没有成功。
以下是一些尝试:
ffmpeg ... "${extension}"
导致:(ffmpeg 1.jpg 2.jpg [...]
发生扩展)
ffmpeg ... ${extension}
相同的
ffmpeg ... '${extension}'
由于搜索模式导致没有文件匹配${extension}
(按字面意思使用变量名)
extension="\'${extension}\'" ; # wrapping the single quotes (preventing expansion) directly in variable
ffmpeg ... ${extension}
'*.jpg'
由于搜索模式(包括单引号)导致没有文件匹配
ffmpeg ... \"${extension}\"
相同但搜索"*.jpg"
(包括双引号)
我终于成功使用了 Shell noglob 选项。
这是好奇的命令:
set -f ; # disable glob (prevent expansion on '*.jpg')
ffmpeg -pattern_type glob -i ${extension} movie.mp4 ;
set +f ; # restore, but what if glob was already disabled? I should not restore it then?
但是出于我的好奇心,是否有另一种方法可以防止来自我们想要解决的变量的脚本参数扩展?(因此,我知道防止扩展(使用单引号)的方式使变量不再解析/替换)。
类似的东西:(但我读到应该避免字符串连接以确保安全,注入)
ffmpeg '${extension}'
|| | 3
|| 2
| 1
在哪里 :
- 1:将为最终结果打开单引号
ffmpeg '*.jpg'
- 2:将我们的变量注入并解析
extension
为.jpg
- 3:会关闭单引号
ffmpeg
来接收参数,就像我手动写的一样'*.jpg'
编辑:在评论如何分配扩展变量后:
local extension="${2}" ;
echo $extension ;
extension="${extension:=jpg}" ; # Default on "jpg" extension
# wrapp extension type in single quotes + prefix with "*."
extension="*.${extension}" ;
然后,将其用于:
runprintcommand ffmpeg -loglevel verbose -pattern_type glob -i ${extension} "$movieName" ;
runprintcommand
函数/脚本在哪里:
function runprintcommand() {
echo "Command to run: (Note: '\\' escape character may not be printed)" ;
echo "$*" ;
$* ;
}
例子:
您的代码中有两个问题会导致 in 的值
$extension
扩展为它包含的 glob 模式,并且还会导致 glob 模式过早地与文件名匹配(您希望将其按原样交给ffmpeg -i
它自己的 glob 扩展内部)。首先是您对函数的调用:
在这里,未加
${extension}
引号,因此您肯定会在其值上发生(分词和)文件名通配符。第二个问题是函数本身:
在这里,您使用
$*
unquoted,即使您${extension}
在函数调用中使用双引号,它也会(将值拆分为单词然后)扩展 glob。$*
使用"$@"
(带双引号)而不是裸露的 。这将扩展到函数的单独引用的位置参数。"$@"
这是和之间的区别"$*"
:"$*"
是一个双引号字符串。这通常不能用于执行带参数的命令。"$@"
是一个双引号单词列表。这可用于执行带有参数的命令。当我发现这样做的另一种语法时,我把它写在这里。
通过使用标志来禁用Shell globbing ( http://tldp.org/LDP/abs/html/globbingref.html ),它确实可以防止扩展:
阻止 shell 通配的方法是引用变量扩展。(它还会停止分词,这通常也是您想要的)。当然,这并不能阻止命令本身处理类似 glob 的模式。
ffmpeg
这样做是为了-i
,所以例如find -name
。以后者为例:(以 a 开头的行
+
fromset -x
,并显示 shell实际运行的命令。)虽然您也可以停止使用 globbing
set -f
,但它对分词没有帮助。如果变量包含空格,则未加引号的扩展将中断,即使使用set -f
.