0

I'm executing a bash script, and need to grab a specific value in a certain line. There can be multiple of these lines per se, although they are in different categories. Here is a sample output:

ffmpeg version N-92906-g54109b1d14 Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 8.2.1 (GCC) 20181201
  configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
  libavutil      56. 25.100 / 56. 25.100
  libavcodec     58. 43.100 / 58. 43.100
  libavformat    58. 25.100 / 58. 25.100
  libavdevice    58.  6.101 / 58.  6.101
  libavfilter     7. 46.101 /  7. 46.101
  libswscale      5.  4.100 /  5.  4.100
  libswresample   3.  4.100 /  3.  4.100
  libpostproc    55.  4.100 / 55.  4.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '.\6 channel.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    creation_time   : 2019-01-31T00:03:03.000000Z
  Duration: 00:00:30.12, start: 0.000000, bitrate: 2527 kb/s
    Stream #0:0: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 960x540 [SAR 1:1 DAR 16:9], 2128 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
    Metadata:
      creation_time   : 2019-01-31T00:03:03.000000Z
      handler_name    : VideoHandler
      timecode        : 00:00:00:00
    Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 98 kb/s (default)
    Metadata:
      creation_time   : 2019-01-31T00:03:03.000000Z
      handler_name    : SoundHandler
    Stream #0:2: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 98 kb/s (default)
    Metadata:
      creation_time   : 2019-01-31T00:03:03.000000Z
      handler_name    : SoundHandler
    Stream #0:3: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 98 kb/s (default)
    Metadata:
      creation_time   : 2019-01-31T00:03:03.000000Z
      handler_name    : SoundHandler
    Stream #0:4: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 98 kb/s (default)
    Metadata:
      creation_time   : 2019-01-31T00:03:03.000000Z
      handler_name    : SoundHandler
    Stream #0:5: Data: none (tmcd / 0x64636D74), 0 kb/s (default)
    Metadata:
      creation_time   : 2019-01-31T00:03:03.000000Z
      handler_name    : TimecodeMediaHandler
      timecode        : 00:00:00:00
Stream mapping:
  Stream #0:2 -> #0:0 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, null, to 'pipe:':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.25.100
    Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s (default)
    Metadata:
      creation_time   : 2019-01-31T00:03:03.000000Z
      handler_name    : SoundHandler
      encoder         : Lavc58.43.100 pcm_s16le
size=N/A time=00:00:30.06 bitrate=N/A speed= 362x
video:0kB audio:5180kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
[Parsed_astats_0 @ 000001e515c90f00] Channel: 1
[Parsed_astats_0 @ 000001e515c90f00] DC offset: 0.000098
[Parsed_astats_0 @ 000001e515c90f00] Min level: -0.394529
[Parsed_astats_0 @ 000001e515c90f00] Max level: 0.380586
[Parsed_astats_0 @ 000001e515c90f00] Min difference: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] Max difference: 0.232958
[Parsed_astats_0 @ 000001e515c90f00] Mean difference: 0.005622
[Parsed_astats_0 @ 000001e515c90f00] RMS difference: 0.010923
[Parsed_astats_0 @ 000001e515c90f00] Peak level dB: -8.078412
[Parsed_astats_0 @ 000001e515c90f00] RMS level dB: -26.826611
[Parsed_astats_0 @ 000001e515c90f00] RMS peak dB: -16.475342
[Parsed_astats_0 @ 000001e515c90f00] RMS trough dB: -85.439368
[Parsed_astats_0 @ 000001e515c90f00] Crest factor: 8.657848
[Parsed_astats_0 @ 000001e515c90f00] Flat factor: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] Peak count: 2
[Parsed_astats_0 @ 000001e515c90f00] Bit depth: 32/32
[Parsed_astats_0 @ 000001e515c90f00] Dynamic range: 215.482282
[Parsed_astats_0 @ 000001e515c90f00] Zero crossings: 109765
[Parsed_astats_0 @ 000001e515c90f00] Zero crossings rate: 0.082774
[Parsed_astats_0 @ 000001e515c90f00] Channel: 2
[Parsed_astats_0 @ 000001e515c90f00] DC offset: -0.000000
[Parsed_astats_0 @ 000001e515c90f00] Min level: -0.000010
[Parsed_astats_0 @ 000001e515c90f00] Max level: 0.000010
[Parsed_astats_0 @ 000001e515c90f00] Min difference: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] Max difference: 0.000016
[Parsed_astats_0 @ 000001e515c90f00] Mean difference: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] RMS difference: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] Peak level dB: -100.304024
[Parsed_astats_0 @ 000001e515c90f00] RMS level dB: -136.845747
[Parsed_astats_0 @ 000001e515c90f00] RMS peak dB: -115.764979
[Parsed_astats_0 @ 000001e515c90f00] RMS trough dB: -1134.435605
[Parsed_astats_0 @ 000001e515c90f00] Crest factor: 67.156208
[Parsed_astats_0 @ 000001e515c90f00] Flat factor: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] Peak count: 2
[Parsed_astats_0 @ 000001e515c90f00] Bit depth: 32/32
[Parsed_astats_0 @ 000001e515c90f00] Dynamic range: 130.387729
[Parsed_astats_0 @ 000001e515c90f00] Zero crossings: 7128
[Parsed_astats_0 @ 000001e515c90f00] Zero crossings rate: 0.005375
[Parsed_astats_0 @ 000001e515c90f00] Overall
[Parsed_astats_0 @ 000001e515c90f00] DC offset: 0.000098
[Parsed_astats_0 @ 000001e515c90f00] Min level: -0.394529
[Parsed_astats_0 @ 000001e515c90f00] Max level: 0.380586
[Parsed_astats_0 @ 000001e515c90f00] Min difference: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] Max difference: 0.232958
[Parsed_astats_0 @ 000001e515c90f00] Mean difference: 0.002811
[Parsed_astats_0 @ 000001e515c90f00] RMS difference: 0.007724
[Parsed_astats_0 @ 000001e515c90f00] Peak level dB: -8.078412
[Parsed_astats_0 @ 000001e515c90f00] RMS level dB: -29.836911
[Parsed_astats_0 @ 000001e515c90f00] RMS peak dB: -16.475342
[Parsed_astats_0 @ 000001e515c90f00] RMS trough dB: -1134.435605
[Parsed_astats_0 @ 000001e515c90f00] Flat factor: 0.000000
[Parsed_astats_0 @ 000001e515c90f00] Peak count: 2.000000
[Parsed_astats_0 @ 000001e515c90f00] Bit depth: 32/32
[Parsed_astats_0 @ 000001e515c90f00] Number of samples: 1326080

I'm thinking to pipe the whole output, get all possible matches, and grab only the last one (corresponding to overall category) and get `RMS level dB: -29.836911 (ignore the first part of line which is ffmpeg version I guess).

How can I get the last line of a match with grep? Or if you know other ways (e.g. sed or awk, that's fine too!)

Tina J
  • 4,983
  • 13
  • 59
  • 125
  • Lots of examples... [Getting the last match in a file using grep](https://serverfault.com/q/197123/145545), [grep last match and it's following lines](https://stackoverflow.com/q/18780395/608639), [Grep after and before lines of last Match](https://stackoverflow.com/q/24422683/608639), [How to find the last match of a string in a bunch of files](https://superuser.com/q/358105/173513) and friends. – jww Feb 13 '19 at 22:47

2 Answers2

2

Pipe the output from grep to tail -1 to get only the last match:

grep <args> | tail -1
infused
  • 24,000
  • 13
  • 68
  • 78
  • I'm having some issues with grep. Why this doesn't work showing only `RMS` lines?! `ffmpeg -i 540p.mp4 -map 0:a:1 -af astats -f null - | grep -i RMS` – Tina J Feb 13 '19 at 22:58
  • 1
    ok, got it. Needed to add some extra stuff: `ffmpeg -i 540p.mp4 -map 0:a:1 -af astats -f null - 2>&1 | grep 'RMS level dB' | tail -1` – Tina J Feb 13 '19 at 23:00
  • 1
    That would be a very slow approach since grep will do a regexp comparison on every line of input, print potentially many lines of output, and then tail will throw all of that effort away except for the last line of output! – Ed Morton Feb 14 '19 at 00:58
  • 1
    Given the use case I don't think performance will be an issue. Maybe if grepping a multi gigabyte file... – infused Feb 14 '19 at 01:05
  • 1
    That may be but we're not answering just for the use case presented in the question but also for the next person who searches the archives for an answer to their own `Get the line of last grep match in bash` problem and does need an efficient approach so it's worth stating. – Ed Morton Feb 14 '19 at 03:24
2
tac file | grep -m 1 <args>

or

ffmpeg <args> | tac | grep -m 1 <args>

to read piped input.

That would be significantly faster than your currently accepted answer of grep | tail. For example:

$ seq 100000000 > file

$ time grep '3' file | tail -1
99999993

real    0m6.781s
user    0m7.500s
sys     0m1.435s

$ time tac file | grep -m 1 3
99999993

real    0m0.046s
user    0m0.015s
sys     0m0.015s
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • Tnx! Will check it out! What is that file? Can you add my ffmepg command to it and have a full answer? – Tina J Feb 14 '19 at 04:37
  • `file` contains the sample input shown in your question. If the input comes directly from a command named `cmd` instead of a file named `file` then just use `cmd | tac | grep` instead of `tac file | grep`. – Ed Morton Feb 14 '19 at 16:49