2

I have been recently introduced to the world of bash scripting. I currently have a video of file which I want to grep the duration. The problem is assigning the duration value to a variable. I get the errors shown below. What is the best way to assign duration value to a variable? Also is it necessary to have two greps. For example the first grep gives duration=171.805000, Then i have to do a second grep for the decimal value only.

snippet

#!/bin/bash/
str_duration=echo$(ffprobe -i "media/myvideo.mp4" -show_format -v quiet | grep duration)
int_duration=echo ${str_duration} | grep -o ' [0-9]\+\.[0-9]\+'

error

line 15: echoduration=171.805000: command not found

command output

ffprobe version git-2014-12-27-d4fd3f2 Copyright (c) 2007-2014 the FFmpeg developers
  built on Dec 27 2014 12:23:47 with gcc 4.8 (Ubuntu 4.8.2-19ubuntu1)
  configuration: --enable-gpl --enable-libfaac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-librtmp --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-nonfree --enable-version3
  libavutil      54. 15.100 / 54. 15.100
  libavcodec     56. 19.100 / 56. 19.100
  libavformat    56. 16.102 / 56. 16.102
  libavdevice    56.  3.100 / 56.  3.100
  libavfilter     5.  6.100 /  5.  6.100
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  1.100 /  1.  1.100
  libpostproc    53.  3.100 / 53.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/media/myvideo.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf56.16.102
  Duration: 00:02:51.81, start: 0.000333, bitrate: 1504 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1367 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 127 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
duration=171.805000
2
  • Can you post the output of ffprobe -i "media/myvideo.mp4" -show_format -v quiet Commented May 1, 2015 at 15:08
  • @Sobrique output posted. Commented May 1, 2015 at 15:12

3 Answers 3

2

So... To answer your question about the error, you need a space after the echo command.

But wait, there's more.

You probably don't really want the word "echo" as part of your duration variable. You'd use echo to display output of some kind, not to gather data and store it in a variable. Variable assignments are in the form of variable=value or read variable which can take a value from a variety of sources.

Note that without the -v quiet, the ffprobe command will dump a plethora of data to stderr, so it's important to include it to reduce the noise of your script.

The output of your (quieted) ffprobe command would include something like this:

duration=171.805000

You can do a number of things with this format of data (my goodness, it looks like variable=value...), but the easiest might be to use cut.

file="media/myvideo.mp4"
str_duration=$(ffprobe -i "$file" -show_format -v quiet | grep ^duration | cut -d= -f2)

Note that this approach of using the equals as a field separator might fail for other fields which might include their own equals sign. But it should be safe for duration.

Alternately, you could use tools like awk or sed to reduce the number of pipes:

str_duration=$(ffprobe -i "$file" -show_format -v quiet | sed -ne '/^duration=/s///p')

or

str_duration=$(ffprobe -i "$file" -show_format -v quiet | awk -F= '$1=="duration"{print $2}')

I am purposely not going to tell you how to use the eval command to take ffprobe's output and assign it directly as a variable within your script, because the eval command is very dangerous if you don't check and limit its input. As a beginning shell programmer, you should read about eval and then not use it until you feel that you're somewhere between "intermediate" and "advanced". :)

Alternately, you can use Input Field Separators to parse this data in bash:

declare -A details
while IFS== read field value; do
  details[$field]="$value"
done < <(ffprobe -i "$file" -show_format -v quiet | grep '.=.')

echo "${details[duration]}"

This takes the output of the ffprobe command and commits it to the elements of an array, which you can read as per the echo line. It is safe for content that includes an equals sign, because of the limited number of variables mentioned in the read command.

Note that except in the case of this last example, ALL the commands in this answer are compatible with traditional /bin/sh, not just bash.

Sign up to request clarification or add additional context in comments.

2 Comments

After some consideration this is the best answer. However I am getting this error line 18: syntax error near unexpected token do' IFS== while read field value; do' and ther is a missing { for echo "${details[duration]"
Ah, a think-o on my part. The IFS assignment needs to be applied to the read command, not the while. I've corrected the error in my answer, please try again with the corrected command line. And thanks! :)
2

Try something like:

str_duration=$(ffprobe -i "media/myvideo.mp4" -show_format -v quiet | grep duration | awk -F'=' '{print $2}')

You dont need echo. Also the output generated by your command is:

duration=171.805000

And you need to assign numbers to str_duration variable and hence with awk you get numbers whatever is after "=".

1 Comment

If you're adding awk to the pipeline anyway, why leave grep in there?
0

I would go with:

duration=$( ffprobe -i "media/myvideo.mp4" -show_format -v quiet | grep duration | sed 's/.*=//g' )

If you wanted 'just' the number:

duration=$( ffprobe -i "media/myvideo.mp4" -show_format -v quiet | grep ^duration | sed -e 's/.*=//' -e 's/\..*//' )

1 Comment

If you're recommending sed, why bother with grep? (... | sed -n '/duration/s.*=//gp')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.