J V
J V

Reputation: 11936

find in bash to convert files with ffmpeg - paths being changed

Trying to convert a bunch of files with ffmpeg and find.

find -name "*.mkv" | while read f
do ffmpeg -i "$f" -c copy -y "${f%.*}.mp4"
done

This should work right? It results in:

+ read f
+ ffmpeg -i '/file.mkv' -c copy -y '/file.mp4'
ffmpeg version N-61155-g61ff043 Copyright (c) 2000-2014 the FFmpeg developers
  built on Mar  7 2014 19:17:59 with gcc 4.8 (Debian 4.8.2-16)
/file.mkv: No such file or directory

So I naturally try sticking the missing dot in front of the variable:

find -name "*.mkv" | while read f
do ffmpeg -i ".$f" -c copy -y ".${f%.*}.mp4"
done

The result:

+ read f
+ ffmpeg -i '../file.mkv' -c copy -y '../file.mp4'
ffmpeg version N-61155-g61ff043 Copyright (c) 2000-2014 the FFmpeg developers
  built on Mar  7 2014 19:17:59 with gcc 4.8 (Debian 4.8.2-16)
../file.mkv: No such file or directory

It's specifically removing the dot at the worst possible time. Any idea what's causing this and how to fix it?

PS: -print0 in find has the same problem, and none of the files have newlines etc.

Edit: As requested, the echo. The echo works as expected:

find -name "*.mkv" | while read f
do echo ffmpeg -i "$f" -c copy -y "${f%.*}.mp4"
done

+ read f
+ echo ffmpeg -i './file.mkv' -c copy -y './file.mp4'
ffmpeg -i ./file.mkv -c copy -y ./file.mp4

Edit2: With a file with a space and one without, the filename without is changed. If I rm the one with a space the one without works fine.

$ ls
+ ls
file.mkv  file two.mkv
$ find -name "*.mkv" | while read f; do ffmpeg -i "$f" -c copy -y "${f%.*}.mp4"; done
+ find -name '*.mkv'
+ read f
+ ffmpeg -i './file two.mkv' -c copy -y './file two.mp4'
ffmpeg version N-61155-g61ff043 Copyright (c) 2000-2014 the FFmpeg developers
  built on Mar  7 2014 19:17:59 with gcc 4.8 (Debian 4.8.2-16)
  configuration: --arch=amd64 --enable-pthreads --enable-libopencv --enable-librtmp --enable-libopenjpeg --enable-libopus --enable-libspeex --enable-libtheora --enable-vaapi --enable-runtime-cpudetect --enable-libvorbis --enable-zlib --enable-swscale --enable-libcdio --enable-bzlib --enable-libdc1394 --enable-frei0r --enable-gnutls --enable-libgsm --enable-libmp3lame --enable-libpulse --enable-vdpau --enable-libvpx --enable-gpl --enable-x11grab --enable-libx264 --enable-filters
  libavutil      52. 66.101 / 52. 66.101
  libavcodec     55. 52.102 / 55. 52.102
  libavformat    55. 33.101 / 55. 33.101
  libavdevice    55. 11.100 / 55. 11.100
  libavfilter     4.  3.100 /  4.  3.100
  libswscale      2.  5.101 /  2.  5.101
  libswresample   0. 18.100 /  0. 18.100
  libpostproc    52.  3.100 / 52.  3.100
Input #0, matroska,webm, from './file two.mkv':
  Metadata:
    COMPATIBLE_BRANDS: isommp42
    MAJOR_BRAND     : mp42
    MINOR_VERSION   : 0
    ENCODER         : Lavf55.33.101
  Duration: 00:08:15.54, start: 0.000000, bitrate: 194 kb/s
    Stream #0:0(und): Audio: aac, 44100 Hz, stereo, fltp (default)
    Metadata:
      CREATION_TIME   : 2014-03-07 04:33:17
      LANGUAGE        : und
      HANDLER_NAME    : IsoMedia File Produced by Google, 5-11-2011
Output #0, mp4, to './file two.mp4':
  Metadata:
    COMPATIBLE_BRANDS: isommp42
    MAJOR_BRAND     : mp42
    MINOR_VERSION   : 0
    encoder         : Lavf55.33.101
    Stream #0:0(und): Audio: aac ([64][0][0][0] / 0x0040), 44100 Hz, stereo (default)
    Metadata:
      CREATION_TIME   : 2014-03-07 04:33:17
      LANGUAGE        : und
      HANDLER_NAME    : IsoMedia File Produced by Google, 5-11-2011
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
Press [q] to stop, [?] for help
size=   11698kB time=00:08:15.53 bitrate= 193.4kbits/s    
video:0kB audio:11614kB subtitle:0 data:0 global headers:0kB muxing overhead 0.724668%
+ read f
+ ffmpeg -i /file.mkv -c copy -y /file.mp4
ffmpeg version N-61155-g61ff043 Copyright (c) 2000-2014 the FFmpeg developers
  built on Mar  7 2014 19:17:59 with gcc 4.8 (Debian 4.8.2-16)
  configuration: --arch=amd64 --enable-pthreads --enable-libopencv --enable-librtmp --enable-libopenjpeg --enable-libopus --enable-libspeex --enable-libtheora --enable-vaapi --enable-runtime-cpudetect --enable-libvorbis --enable-zlib --enable-swscale --enable-libcdio --enable-bzlib --enable-libdc1394 --enable-frei0r --enable-gnutls --enable-libgsm --enable-libmp3lame --enable-libpulse --enable-vdpau --enable-libvpx --enable-gpl --enable-x11grab --enable-libx264 --enable-filters
  libavutil      52. 66.101 / 52. 66.101
  libavcodec     55. 52.102 / 55. 52.102
  libavformat    55. 33.101 / 55. 33.101
  libavdevice    55. 11.100 / 55. 11.100
  libavfilter     4.  3.100 /  4.  3.100
  libswscale      2.  5.101 /  2.  5.101
  libswresample   0. 18.100 /  0. 18.100
  libpostproc    52.  3.100 / 52.  3.100
/file.mkv: No such file or directory
+ read f

Upvotes: 1

Views: 1701

Answers (2)

Pat
Pat

Reputation: 23

Alternatively, you could execute ffmepg on each file as it's found:

find . -type f -name "*.mkv" -exec bash -c 'ffmpeg -i "$0" -codec copy "${0%.*}.mp4"' "{}" \;

Upvotes: 0

chepner
chepner

Reputation: 531075

ffmpeg, for reasons I do not know, reads from standard input. Redirect from /dev/null to avoid interfering with the read statement in the while loop.

find -name "*.mkv" | while read f
do ffmpeg -i "$f" -c copy -y "${f%.*}.mp4" < /dev/null
done

Upvotes: 4

Related Questions