LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.

Notices


Reply
  Search this Thread
Old 05-19-2018, 04:24 PM   #1
markus-n
LQ Newbie
 
Registered: Apr 2014
Distribution: Xubuntu, Arch
Posts: 20

Rep: Reputation: Disabled
bash: How can executing an external command confuse a while (read lines from file) loop?


Hi,

I have a set of corrupted .mp4 videos and I wrote a bash script to fix them using ffmpeg. Fortunately, only the container is corrupted, and the streams are OK. While fixing, I would like to add titles that are read from a .m3u playlist.

The script reads the .m3u file line by line, ignores empty lines and the leading #EXTM3U, and then it depends on the line content:
If the line contains "EXTINF:", the title is extracted from that line, remembered, and used for the next line that contains a file name. With that information, ffmpeg is executed. No one alters the input .m3u file.

The problem is:
After the first time ffmpeg is really executed, the lines read from the .m3u are incomplete, trimmed or whatever. If I comment out the line executing ffmpeg, the file is parsed as expected.


This is a shortened version of the .m3u playlist:
Code:
#EXTM3U

#EXTINF:2886,01 Premiere
01_Premiere.mp4

#EXTINF:2913,02 Das Leben soll nicht enden
02_Das_Leben_soll_nicht_enden.mp4

#EXTINF:2813,03 Gefährlicher Besucher an Bord
03_Gefaehrlicher_Besucher_an_Bord.mp4
I have verified that it only has unix/Linux file endings (LF).

And this is the script (whith ffmpeg commented out):
Code:
#!/bin/bash

delimiter() {
  echo "================================================================================"
}

INPUTFILE=$1
TARGETDIR=$2

if [ "$INPUTFILE" == "" -o "$TARGETDIR" == "" ]
then
  echo "Input-File and/or target-dir missing."
  exit 1
fi

CURRENT_TITLE=

while read INPUT_LINE
do
  if [ "$INPUT_LINE" == "" -o "$INPUT_LINE" == "#EXTM3U" ]
  then
    continue
  fi

  delimiter
  echo "LINE=\"$INPUT_LINE\""

  if [[ $INPUT_LINE =~ EXTINF: ]]
  then
    CURRENT_TITLE="`echo "$INPUT_LINE" | sed -e 's/.*#EXTINF:[0-9]*,//;'`"
    echo "TITLE=$CURRENT_TITLE"
  else
    if [ -f "$INPUT_LINE" ]
    then
      if [ "$CURRENT_TITLE" != "" ]
      then
        OUTPUTFILE="${TARGETDIR}/${INPUT_LINE##*/}"
        echo "$INPUT_LINE -> $CURRENT_TITLE"
#        ffmpeg -i "$INPUT_LINE" -loglevel quiet -c copy -metadata title="$CURRENT_TITLE" "$OUTPUTFILE"
      else
        echo "ERROR: no current title for file \"$INPUT_LINE\"."
        exit 1
      fi
    else
      echo "ERROR: line \"$INPUT_LINE\" is neither title nor file."
      exit 1
    fi
    CURRENT_TITLE=
  fi
done < <(cat "$INPUTFILE")
As you see, it has some diagnostic echo's.

This is the expected output that I only can achieve with ffmpeg commented out:
Code:
================================================================================
LINE="#EXTINF:2886,01 Premiere"
TITLE=01 Premiere
================================================================================
LINE="01_Premiere.mp4"
01_Premiere.mp4 -> 01 Premiere
================================================================================
LINE="#EXTINF:2913,02 Das Leben soll nicht enden"
TITLE=02 Das Leben soll nicht enden
================================================================================
LINE="02_Das_Leben_soll_nicht_enden.mp4"
02_Das_Leben_soll_nicht_enden.mp4 -> 02 Das Leben soll nicht enden
================================================================================
LINE="#EXTINF:2813,03 Gefährlicher Besucher an Bord"
TITLE=03 Gefährlicher Besucher an Bord
================================================================================
LINE="03_Gefaehrlicher_Besucher_an_Bord.mp4"
03_Gefaehrlicher_Besucher_an_Bord.mp4 -> 03 Gefährlicher Besucher an Bord
But with the ffmpeg line being active, it looks like this:
Code:
================================================================================
LINE="#EXTINF:2886,01 Premiere"
TITLE=01 Premiere
================================================================================
LINE="01_Premiere.mp4"
01_Premiere.mp4 -> 01 Premiere
================================================================================
LINE="oll nicht enden"
ERROR: line "oll nicht enden" is neither title nor file.
So, the line
Code:
#EXTINF:2913,02 Das Leben soll nicht enden
is trimmed to
Code:
oll nicht enden
and therefore not recognized as #EXTINF.

What did I miss ?

Regards,
Markus

Last edited by markus-n; 05-20-2018 at 12:24 AM.
 
Old 05-19-2018, 06:11 PM   #2
RandomTroll
Senior Member
 
Registered: Mar 2010
Distribution: Slackware
Posts: 1,953

Rep: Reputation: 270Reputation: 270Reputation: 270
Instead of commenting-out the ffmpeg line, echo it, capture the output.
 
Old 05-19-2018, 06:34 PM   #3
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,776

Rep: Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212
If the invoked command reads from stdin, that is going to absorb some of the input. I'm not sure why ffmpeg would be doing that, but just redirect its stdin from /dev/null:
Code:
ffmpeg ... <dev/null
 
Old 05-20-2018, 12:24 AM   #4
markus-n
LQ Newbie
 
Registered: Apr 2014
Distribution: Xubuntu, Arch
Posts: 20

Original Poster
Rep: Reputation: Disabled
Whow, that's it !
Looks like ffmpeg indeed reads from stdin. Redirecting as you suggested is the solution.

Thank you very much.
 
Old 05-21-2018, 04:03 AM   #5
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,781

Rep: Reputation: 1199Reputation: 1199Reputation: 1199Reputation: 1199Reputation: 1199Reputation: 1199Reputation: 1199Reputation: 1199Reputation: 1199
Two comments.
Code:
done < <(cat "$INPUTFILE")
is complicated+slow for
Code:
done < "$INPUTFILE"
In some cases it is advisable to use another file descriptor for the read command (would help here as well, but the </dev/null is the better work around)
Code:
while read INPUT_LINE <&3
do
 ... 
done 3< "$INPUTFILE"
 
Old 05-21-2018, 06:52 AM   #6
Chevron7
LQ Newbie
 
Registered: May 2016
Location: UK
Distribution: Debian
Posts: 5

Rep: Reputation: Disabled
Also, ffmpeg has the option -nostdin to prevent it reading from stdin.
 
1 members found this post helpful.
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
how to loop over text file lines within bash script for loop? johnpaulodonnell Linux - Newbie 9 07-28-2015 03:49 PM
[SOLVED] read filename from the command prompt and display the number of lines in file hd_pulse Programming 9 05-30-2011 09:39 PM
bash - difference between executing program in for loop and typing each command? jlarsen Programming 14 11-10-2008 05:38 PM
Executing command lines in C/C++ ReverseLogic Programming 2 05-28-2002 02:08 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - General

All times are GMT -5. The time now is 06:19 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration