Following command tells me the length of mp4 video files:

find -type f -name "*.mp4" -print0 | \
   xargs -0  mplayer -vo dummy -ao dummy -identify 2>/dev/null | \
   perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t +=$1) && printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60' | \
   tail -n 1

Can someone parse it and explain why it is the way it is?

It would also be helpful to know how to use it again and again without retyping it or through copy-and-paste.

  • For the record, you can also get the duration (in seconds) of a mp4 file or any audio/video file with exiftool -p '$Duration#' file.mp4 Jan 25, 2013 at 21:56
  • @Stephane You would have to tweak a little bit more to get the same output (i.e. the total length of all mp4 files).
    – xyz
    Jan 26, 2013 at 0:06

1 Answer 1

find -type f -name "*.mp4" -print0

Recursively search the current directory for normal files whose names end with .mp4 and print their relative path names, separated by null bytes. -print0 is safer than -print here, because newlines are valid characters in a filename. find(1)

| xargs -0

Use the input as arguments to the next command. Input is null-separated. xargs(1)

mplayer -vo dummy -ao dummy -identify 2>/dev/null

This is the command that xargs is running. Using dummy video and audio drivers, show file parameters in an easily parseable format. Discard any output from STDERR. mplayer(1)

| perl -nle

Pipe the output to Perl. Perl will read lines of input into the $_ variable, stripping newlines from the end. perlrun(1)


If the line matches this regular expression, capture the number following "ID_LENGTH=",

&& ($t +=$1)

then increase the variable $t by the number captured in the first match,

&& printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60'

and calculate hours, minutes, and seconds from $t, which is a count of seconds. Because of the -l in the perl invocation, a newline is added automatically to print statements, but not printf, so the format string contains one ("\n").

| tail -n 1

Only print the last line of output. tail(1)

To make this pipeline into a single command, you can create a shell function in your .bashrc or whatever rc-file your shell uses. Here's an example:

vid_lengths() {
  find -type f -name "*.mp4" -print0 \
    | xargs -0  mplayer -vo dummy -ao dummy -identify 2>/dev/null \
    | perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t +=$1) && printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60' \
    | tail -n 1
  • @AdrianPronk You're right, and I should have caught that. Corrected. Jan 30, 2013 at 3:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .