0

The original problem

This may be more of a bc or bash question than an FFmpeg one, although I would also appreciate being able to prevent ffprobe from printing carriage returns after its output.

In a script I'm writing to automate some common tasks with FFmpeg, I'm getting the length of two files using the following:

length1="$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 \"$1\")"
length2="$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 outro.mp4)"
read -p "Enter the desired duration of the fade in seconds: " fadeduration

...which outputs successfully as:

$ echo $length1; echo $length2
177.800000
10.567000
<USER INPUT; usually a 2 followed by ENTER>

However, attempting to perform basic calculations on these variables with bc:

total=$(echo "$length1 +$length2" - "$fadeduration" | bc)
echo $total 

...results in an empty variable.

Troubleshooting process

I tried to break the command down into simpler parts, and even this failed:

$ echo "$length1 + $length2" | bc
(standard_in) 1: illegal character: ^M
(standard_in) 1: illegal character: ^M

This was because, for some reason, the ffprobe commands (at least in my MSYS2-built binary) add a Windows line ending to the end of the output, and therefore the variables.

I fixed this problem by piping the output through tr to strip it of carriage returns:

echo "$length1 + $length2" | tr -d $'\r' | bc

The current problem

But doing the same thing with my original calculation still doesn't work:

$ echo "$length1 + $length2 - $fadeduration" | tr -d $'\r' | bc
(standard_in) 2: syntax error

This time bc returns a syntax error, suggesting that a) I'm getting somewhere, and b) it's a problem with how I've written it.

How can I do this calculation in bc so that it successfully populates my variable?

Posting in line the output as seen by od -c

$ echo "$length1 + $length2 - $fadeduration" | od -c
0000000   1   7   7   .   8   0   0   0   0   0  \r       +       1   0
0000020   .   5   6   7   0   0   0  \r       -      \n
Hashim Aziz
  • 13,835

2 Answers2

1

ffprobe is a Windows program, so its output contains CR (Carriage Return) and LF (Line Feed).

CR LF is the sequence \r  \n

I have not ffprobe but any Windoes program can show the same

$ touch prova.txt
$ cmd /c dir prova.txt | od -c
0000000       D   a   t   e   n   t   r 204   g   e   r       i   n
0000020   L   a   u   f   w   e   r   k       D   :       i   s   t
0000040   D   A   T   A  \r  \n       V   o   l   u   m   e   s   e   r
...

bc requires that the command is terminated with "\n"

$ echo -e  "2+4"  | od -c
0000000   2   +   4  \n
0000004
$ echo -e  "2+4"  | bc
6

missing it, bc reports an error

$ echo -e  -n "2+4"  | od -c
0000000   2   +   4
0000003
$ echo -e  -n "2+4"  | bc
(standard_in) 1: syntax error

Verify with od -c the contents of echo "$length1 + $length2 - $fadeduration" probably it is missing the final \n, or there are too many

In the first case you can use, something like

total=$(echo "$length1 + $length2 - $fadeduration \n" | bc)

otherwise try cleaning the variables at origin with

length1="$(ffprobe -v erro .. | tr -d '\r')
matzeri
  • 2,531
1

This is one of those very rare situations where not enclosing variables in double-quotes will achieve what you need.

Usually I would say (repeatedly!) that variables should be in double-quotes whenever used, so as to prevent the shell from splitting the values on whitespace. However, in this situation you can usefully let the shell split the values on whitespace as this includes not only newline but also carriage return,

total=$(echo $length1 + $length2 - $fadeduration | bc)
echo $total

Note that for this to work you need to have modified IFS to include \r in the set of whitespace characters it parses. I've done this long-since on Cygwin, which is why I'd forgotten about it when I first posted this answer:

export IFS=$' \t\r\n'    # bash or other shells understanding $'...' syntax

Looking at the od -c output, you can see that it ends with the minus symbol, i.e. you have no numeric value for $fadeduration. This explains the syntax error from bc (1 + 2 - isn't valid). Your code to read the value is correct (read -p 'Prompt... ' fadeduration) so perhaps in the second part of your testing you simply forgot to set the value?

Chris Davies
  • 4,560