简体   繁体   中英

Assign variable the grep value of command output

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

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 "=".

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.

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/\..*//' )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM