find:使用子进程时缺少`-exec'的参数

时间:2017-07-12 07:48:53

标签: python bash python-3.x ffmpeg

"find / -name 'testmkv-27311.mkv' -exec bash -c 'ffmpeg -i testmkv-27311.mkv -vcodec copy -acodec copy -codec:v libx264 -profile:v high -preset slow -b:v 500k -maxrate 500k -bufsize 1000k -vf scale=-1:480 -threads 0 -codec:a libfdk_aac -b:a 128k {}testmkv-27311.mp4' \;"
  

是我传递的命令,它给出了错误的查找...已经有一些关于它的答案但它们没有说清楚......请帮我执行这个命令......

1 个答案:

答案 0 :(得分:2)

即时问题:Shell引用与Python引用

在shell中的未加引号的上下文中,\;阻止将;解析为命令分隔符。但是,在没有shell=True的情况下从Python调用带有参数列表的命令时, 没有shell来解释和删除该反斜杠,并且额外的引用使行为等同于传递{{1}在shell中 - 意味着传递给'\;'的参数不是它期望的确切字符串find,并且您得到语法错误。

但是,原始代码在其他方面也是不正确的(在影响安全的方面!);应使用以下解决方案之一。

最小的变化:安全地使用;

就个人而言,如果你愿意对输出名称(即find)稍微有点灵活,我会写得更像以下内容:

testmkv-27311.mkv.avi

值得注意的是:

  • 我们调用shell,从而避免了shell注入式安全漏洞。
  • 引用完全是使用Python语法完成的 - 不使用或不需要嵌套的shell引用。
  • POSIX不要求subprocess.call([ 'find', '/', '-name', 'testmkv-27311.mkv', '-exec', 'ffmpeg', '-i', '{}', '-vcodec', 'copy', '-acodec', 'copy', '-codec:v', 'libx264', '-profile:v', 'high', '-preset', 'slow', '-b:v', '500k', '-maxrate', '500k', '-bufsize', '1000k', '-vf', 'scale=-1:480', '-threads', '0', '-codec:a', 'libfdk_aac', '-b:a', '128k', '{}.mp4', ';', ]) 支持find -exec作为子字符串(而不是完整的参数)。因此,这个答案(就像问题中的代码一样)并不像人们希望的那样便携。

替代方法:原生Python文件搜索

也就是说,根本没有令人信服的理由使用{},当Python标准库可以对你进行搜索时,可以很容易地更新自己命名:

find

备用安全方法:在参数上迭代的硬编码脚本

另一种安全地执行此操作的方法(def convert(filename_in, filename_out): subprocess.call([ 'ffmpeg', '-i', filename_in, '-vcodec', 'copy', '-acodec', 'copy', '-codec:v', 'libx264', '-profile:v', 'high', '-preset', 'slow', '-b:v', '500k', '-maxrate', '500k', '-bufsize', '1000k', '-vf', 'scale=-1:480', '-threads', '0', '-codec:a', 'libfdk_aac', '-b:a', '128k', filename_out, ]) target = 'testmkv-27311.mkv' for root, dir, files in os.walk('/'): if target in files: filename_in = os.path.join(dir, target) filename_out = filename_in[:-3]+'.mp4' convert(filename_in, filename_out) 修改或生成名称中的代码,允许这些名称被shell解析为代码),您可以拥有你的bash脚本迭代它的参数:

find

在这种情况下,bash_script=r''' for filename; do ffmpeg -i "$filename" \ -vcodec copy \ -acodec copy \ -codec:v libx264 \ -profile:v high \ -preset slow \ -b:v 500k \ -maxrate 500k \ -bufsize 1000k \ -vf scale=-1:480 \ -threads 0 \ -codec:a libfdk_aac \ -b:a 128k \ "${filename%.mkv}.mp4}" done ''' subprocess.call([ 'find', '/', '-name', 'testmkv-27311.mkv', '-exec', 'bash', '-c', bash_script, '_', '{}', '+']) 是脚本中_的占位符;后续参数($0找到的文件名)在find$1等中传递; $2(默认为for filename; do)会迭代它们。

使用for filename in "$@"; do传递尽可能多的文件名到每个命令,而不是每个文件名调用一次命令;这减少了调用的shell数量,从而提高了性能。