4

I'm iterating through an array of integers ${startTimes} (marker locations in an audio file, in samples) and using bc to convert those integers to milliseconds. I'm passing the results into a new array ${msValuesArray}. If I run each array element one at a time it works fine. If I run it in a for loop:

for i in $(seq 0 ${#startTimes[@]}); do 
    msValuesArray+=($(bc <<< ${startTimes[i]}/44.1))
done

The resulting ${msValuesArray} contains the expected results, but the terminal outputs (standard_in) 1: parse error.

While I intend to use this in a shell script, and after reading other questions here I learned that adding #!/bin/bash to the beginning of the command avoids the parse error, I still don't understand the following:

a) why does the manual passing of a ${startTimes} element into bc work without the parse error while the for loop also works, yet outputs the parse error (outside of the shell script)?

b) despite the parse error, I have the resulting array that I want. Should I ignore the error?

c) when adding #!/bin/bash to the beginning of the commands (still outside of the shell script, just in the command line) why are the results inaccessible? (Entering echo ${msValuesArray[@]} returns an empty array.)

d) While running inside the shell script, is the same error happening but just not printing to the terminal?

Any help is appreciated. Thanks.

3
  • What does the starts array look like? Does it have the same number of elements as startTimes? Is this your whole script? How do you run it? What do you mean by "adding #!/bin/bash in the command line"? Commented Aug 28, 2017 at 21:22
  • Sorry, bad copy/paste. I just fixed it. It's supposed to be startTimes. I don't have the whole script yet, just testing out commands one at a time in the command line to make sure my script will run (if there's a better method I'm all ears). For the shebang, if I enter all of this #!/bin/bash; for...(etc)...; done in the command line I get no parse error -- but also no accessible results. I'm assuming it's running in another shell that I can't access? Still learning, obviously. Commented Aug 28, 2017 at 21:28
  • And if it helps, startTimes looks like this: 0 87053 91463 190062 194472 290520 294930 387582 391992. Just a bunch of integers. Commented Aug 28, 2017 at 21:30

2 Answers 2

4

You can iterate over the array directly instead of going via indices:

for t in "${startTimes[@]}"; do
    msValuesArray+=($(bc <<< "$t / 44.1"))
done

This makes the loop easier to read.

You get a parse error because you're trying to access a non-existing element (see John1024's answer), so bc sees just / 44.1. You shouldn't ignore the error.

You should quote your here-string, even though in this very instance it doesn't seem to cause problems1.

If you enter #!/bin/bash just on the command line, it has no effect at all, it's just considered a comment. It only does something as the first line of a script, namely indicate what interpreter should be used. If, as indicated by your comment, you enter the whole thing on a single line as

#!/bin/bash; for ... (etc) ...

nothing at all happens. It's just a comment.

Lastly, you're truncating your results. If you want them more precise, you can set scale to a sensible value, as in

bc <<< "scale = 3; $t / 44.1"

1 Problems such as (unwanted) word splitting and globbing. This article is a good overview about the how and why of quoting.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks very much! Can you elaborate on the importance of quotes for the here-string? I'm still fuzzy on quote usage, in general.
@Urphänomen I've added a link to a good article about quoting. The rule of thumb is really "if in doubt, quote".
Excellent, thank you @Benjamin W. An overview is just what I need, much appreciated.
@Urphänomen Benjamin's solution of for t in "${startTimes[@]}" appears to me to be a good one. I recommend that you accept his answer.
4

You have an off-by-1 problem. Observe that, with your sample startTimes, seq generates 10 numbers:

$ startTimes=(0 87053 91463 190062 194472 290520 294930 387582 391992)
$ seq 0 ${#startTimes[@]}
0
1
2
3
4
5
6
7
8
9

The problem is that startTimes has only 9 entries:

$ declare -p startTimes
declare -a startTimes=([0]="0" [1]="87053" [2]="91463" [3]="190062" [4]="194472" [5]="290520" [6]="294930" [7]="387582" [8]="391992")

When i=9, startTimes[9] evaluates to an empty string and that leads to the bc error that you see:

$ i=9; msValuesArray+=($(bc <<< ${startTimes[i]}/44.1))
(standard_in) 1: syntax error

Or, more directly:

$ bc <<<"/44.1"
(standard_in) 1: syntax error

1 Comment

Thank you! Very helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.