如何在使用find -exec命令时使用原始文件名?

5

我想要转换一些.mp4文件。

$ find . -name '*.mp4'
./01.mp4
./02.mp4
./03.mp4

我期望使用这个命令输出文件copy-01.mp4copy-02.mp4copy-03.mp4

find . -name '*.mp4' -exec ffmpeg -i {} -c copy -aspect 16:9 copy-{} ";"

但是它失败了,出现了错误:无法找到适合的输出格式'copy-'。 我认为{}代表文件名,不是吗?

当使用find命令的-exec选项时,我该如何使用原始文件名?

find命令的版本是:

$ find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Built using GNU gnulib version e5573b1bad88bfabcda181b9e0125fb0c52b7d3b
Features enabled: O_NOFOLLOW(disabled) LEAF_OPTIMISATION FTS() CBO(level=0)

这是 xargs 的版本。

xargs --version
xargs (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Built using GNU gnulib version e5573b1bad88bfabcda181b9e0125fb0c52b7d3b

ffmpeg的结果

$ find * -type f -name '*.mp4' -exec ffmpeg -i {} -c copy -aspect 16:9 copy-{} ";"

# almost same outputs several times here.

ffmpeg version N-50911-g9efcfbe Copyright (c) 2000-2013 the FFmpeg developers
  built on Mar 13 2013 21:26:48 with gcc 4.7.2 (GCC)
  configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-libass --enable-libbluray --enable-libcaca --enable-libfreetype --enable-libgsm --enable-libilbc --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid --enable-zlib
  libavutil      52. 19.100 / 52. 19.100
  libavcodec     55.  0.100 / 55.  0.100
  libavformat    55.  0.100 / 55.  0.100
  libavdevice    54.  4.100 / 54.  4.100
  libavfilter     3. 45.103 /  3. 45.103
  libswscale      2.  2.100 /  2.  2.100
  libswresample   0. 17.102 /  0. 17.102
  libpostproc    52.  2.100 / 52.  2.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '24.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: mp42isomavc1
    creation_time   : 2012-11-01 13:42:12
    encoder         : HandBrake 0.9.8 2012071700
  Duration: 00:24:58.62, start: 0.000000, bitrate: 474 kb/s
    Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 640x256, 341 kb/s, 29.97 fps, 29.97 tbr, 90k tbn, 180k tbc
    Metadata:
      creation_time   : 2012-11-01 13:42:12
    Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 127 kb/s
    Metadata:
      creation_time   : 2012-11-01 13:42:12

你是否想知道为什么会出现这种错误——可能是 {} 为空?你可以尝试以下命令:find . -name '*.mp4' -exec echo MyFile: {} ";" - AndreyS Scherbakov
1
为什么使用这么旧的 ffmpeg 版本?请参考 FFmpeg 下载 页面获取最新版本的链接。 - llogan
4个回答

3

最好的方法是编写一个Bash脚本。问题在于当前目录前缀为./

如果你真的必须这样做,可以执行以下操作:

find * -type f -name '*.mp4' -exec ffmpeg -i {} -c copy -aspect 16:9 copy-{} ";"

如果您有xargs,那么您也可以这样做:
find . -name '*.mp4' | xargs -L1 basename | xargs -L1 -I{} ffmpeg -i {} -c copy -aspect 16:9 copy-{}

谢谢,但第一个命令返回相同的错误信息“无法找到适合 'copy-' 的输出格式”,而第二个命令则返回“xargs: {}: 没有那个文件或目录”的错误信息。我正在使用Railsinstaller/Devkit命令,关于这些命令的更多细节我将在我的问题中添加。 - ironsand
很奇怪,我有相同的版本,两个命令都可以工作。你能在问题中发布完整的ffmpeg控制台输出吗? - aergistal

1
要让ffmpeg访问文件,即使它们在当前目录的几个目录级别之后,您需要将整个源路径作为-i参数传递,但只使用基本名称作为目标文件名构建块。
如果您想将它们复制到当前目录(扁平化),
find . -type f -name '*.mp4' -exec ffmpeg -i {} -c copy -aspect 16:9 copy-"`basename {}`" ";"

如果它们应该放置在与源文件相同的目录中:
find . -type f -name '*.mp4' -exec ffmpeg -i {} -c copy -aspect 16:9 "`dirname {}`"/copy-"`basename {}`" ";"

谢谢,但是在我的环境中basename不起作用。find . -type f -name '*.mp4' -exec echo basename {} ";"返回./01.mp4./02.mp4。但是basename './01.mp4'返回01.mp4 - ironsand
你是否两次引用了basename:.... echo "`basename`"(注意反单引号)? - AndreyS Scherbakov
啊,我只引用了一次basename. 第一个引用是为了在StackOverflow中使用Markdown. 我不知道如何避免Markdown... - ironsand

1

这并不是适合用一行代码解决的工作。试试用脚本:

#!/bin/bash
while IFS= read -r -d '' FILE
do
    BASE=$(basename "$FILE")
    COPYFILE=${FILE/$BASE/copy-$BASE}
    ffmpeg -i "$FILE" -c copy -aspect 16:9 "$COPYFILE"
done < <(find . -name '*.mp4' -print0)

(当然,如果你真的想要的话,只需加上几个分号,就可以将这段代码放在一行上!)

你的脚本在我的环境中无法正常工作,但知道没有简单的方法可以用一行代码完成还是很好的。我为此编写了一个 Ruby 脚本。Dir.glob("*.mp4").each{|file| system("ffmpeg -i #{file} -c copy -aspect 16:9 copy_#{file}") } - ironsand

0

使用shell参数扩展,这种风格会更好。

find * -type f -name '*.mp4' -exec sh -c 'ffmpeg -i $0 -c copy -aspect 16:9 copy-$0' {} \;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接