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
Kamil Maciorowski
  • 69,815
  • 22
  • 136
  • 202
Hashim Aziz
  • 11,898
  • 35
  • 98
  • 166
  • pipe the echo into `cat -vet` which shows all the special characters, with `$` at the end. – meuh May 08 '21 at 09: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? ` – Hashim Aziz May 08 '21 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. – Hashim Aziz May 08 '21 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? – Kamil Maciorowski May 08 '21 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. – Hashim Aziz May 08 '21 at 23:10
  • @KamilMaciorowski In any case, running the script again now it seems that the `$total` variable is working as is - even when the same line fails with a syntax error on the terminal itself: `total=$(echo "$length1 + $length2 - $fadeduration" | tr -d $'\r' | bc)`. This has been a very weird issue, but all I can gather is that at some point the issue with the script became solved, and my testing that line in the terminal resulted in an invalid syntax error of its own... although I really have no idea why the same line would run fine in a script and cause errors in the terminal. – Hashim Aziz May 08 '21 at 23:12

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,347
  • 2
  • 11
  • 14
  • I'm assuming you meant verify with `od -c` rather than `oc.` This is the [output](https://pastebin.com/qDgcv92T) of piping the command through `od -c`, though I can't really make sense of it. – Hashim Aziz May 08 '21 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 May 08 '21 at 18:56
  • 1
    "probably it is missing the final `\n`" – Impossible regardless of the input because `echo` (without `-n`) always appends a newline. – Kamil Maciorowski May 08 '21 at 20:00
  • @matzeri Nope, I've been hitting 2 and then Enter. – Hashim Aziz May 08 '21 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 May 09 '21 at 09: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?

roaima
  • 2,889
  • 1
  • 13
  • 27