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
6
  • pipe the echo into cat -vet which shows all the special characters, with $ at the end.
    – meuh
    Commented May 8, 2021 at 9:58
  • @KamilMaciorowski Doing what @meuh says does appear to suggest this is the case, as did my debugging, but I assumed the cause of the variable not being set was the syntax error I'm getting from bc. Why else would a variable fail to set? ` Commented May 8, 2021 at 18:01
  • @KamilMaciorowski I see. I completely forgot to include the source of fadeduration in the question but it comes from user input: read -p "Enter the desired duration of the fade in seconds: " fadeduration. For these tests I've been typing the value 2 and pressing Enter. Commented May 8, 2021 at 18:31
  • 1
    Formal note: relevant information belongs to the question. Posting it as a link in a comment under an answer was very unfortunate. I totally missed it, acknowledged your read and therefore assumed the hypothesis from my first comment (now deleted) was wrong. Now I see $fadeduration expands to an empty string. What is the question not telling us? Do you run read in a subshell maybe? Commented May 8, 2021 at 19:52
  • @KamilMaciorowski No, no subshells. The link you're referring to was the result of a command that the answerer requested, hence why I posted it as a comment to his answer. In addition $fadeduration seemed to retain its value when echoed out before the FFmpeg command - all variables except $total did. Commented May 8, 2021 at 23:10

2 Answers 2

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')
5
  • I'm assuming you meant verify with od -c rather than oc. This is the output of piping the command through od -c, though I can't really make sense of it. Commented May 8, 2021 at 18:06
  • 1
    $fadeduration is empty. bc is complaying about the last - without an operator immediately after. Are you just hitting Enter without giving a number ?
    – matzeri
    Commented May 8, 2021 at 18:56
  • 1
    "probably it is missing the final \n" – Impossible regardless of the input because echo (without -n) always appends a newline. Commented May 8, 2021 at 20:00
  • @matzeri Nope, I've been hitting 2 and then Enter. Commented May 8, 2021 at 22:55
  • From the value of $fadeduration it seems or that is not correct or that somewhere you are clearing its content. read works fine for me.
    – matzeri
    Commented May 9, 2021 at 9:29
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?

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .