2

This fails:

#!/bin/bash

N_TIMES="$1"
for ((n = 0; n < $N_TIMES; n++)); do
  # command
done

Setting the variable manually also fails:

#!/bin/bash

N_TIMES=10
for ((n = 0; n < $N_TIMES; n++)); do
  # command
done

Both return:

 Syntax error: Bad for loop variable

Why isn't the loop able to read the variable as a number for iteration? How should it be to be able to read the first argument as the number of times to run the command?

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
YFl
  • 845
  • 7
  • 22
  • `sh` ([Bourne-shell](https://en.wikipedia.org/wiki/Bourne_shell)) is usally not `bash` ([Bourne-again shell](https://en.wikipedia.org/wiki/Bash_(Unix_shell))). – Cyrus Apr 27 '23 at 17:08
  • ...to make things even more complex, `sh` (POSIX sh, a specification from the early 90s that's most directly influenced by late-80s iterations of David Korn's ksh) isn't Bourne (Stephen Bourne's shell from the 1970s) on any modern OS. "Bourne again" is a cute pun, but somewhat misleading. – Charles Duffy Apr 27 '23 at 17:08
  • 1
    (have I mentioned how glad I am that it's no longer the early 2000s when SunOS prevented me from making that "any modern OS" claim? Good riddance, &c) – Charles Duffy Apr 27 '23 at 17:14

1 Answers1

3

warning If you use sh script, you pass the script in POSIX mode, even with bash shebang #!/bin/bash.

The shebang is only used when you don't start an interpreter yourself: when you start an interpreter yourself, the OS doesn't have to do it for you, so nothing looks at the shebang.
It's pretty like the same as compiling with a compiler.

So, don't use:

sh script.sh

to execute script.

note Instead, do:

chmod +x script.sh
./script.sh

On my Debian like OS:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 oct.  28 04:48 /bin/sh -> dash*

Moreover, don't use UPPER case variables


Finally:

#!/usr/bin/env bash

n_times=10
for ((n=0; n < n_times; n++)); do
  # command
done

No need sigil $ in arithmetic.

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • 1
    Specifically, the observed error is what `dash` reports; OP's `/bin/sh` is likely a link to `dash`. – chepner Apr 27 '23 at 16:56
  • you mean, that when I run sh something, even with the shebang it will use the default shell? – YFl Apr 27 '23 at 16:57
  • If you use `sh script`, you pass the script in `POSIX` mode, even with `bash` shebang – Gilles Quénot Apr 27 '23 at 16:58
  • Thanks. what do you mean by "you pass the script in POSIX mode"? – YFl Apr 27 '23 at 16:59
  • @YFl, `sh` is only guaranteed, on a POSIX-compliant operating system, to be a POSIX-compliant shell. It might be dash. It might be bash in sh mode. It might be ksh. It might be posh. It can be _anything_ as long as it's POSIXy. – Charles Duffy Apr 27 '23 at 16:59
  • 1
    @YFl, so you can only safely use `sh` if your code is written to be compatible with every existing POSIX-flavored shell -- which is to say, it needs to be code written to the POSIX sh standard. If you use `#!/bin/bash`, that's saying that your script **isn't** written for `sh`, so you can't safely use `sh` to run it. It's like trying to use a C compiler to compile C++ code. – Charles Duffy Apr 27 '23 at 17:00
  • ok. got you. So when I run `sh ...` I get the default POSIX-compliant shell in the given system, whatever it is. It will overwrite the shebang. Did I understand correctly? – YFl Apr 27 '23 at 17:02
  • 2
    @YFl, exactly right. The shebang is only used when you don't start an interpreter yourself; when you start an interpreter yourself, the OS doesn't have to do it for you, so nothing looks at the shebang. – Charles Duffy Apr 27 '23 at 17:02
  • 1
    Perfect. That's correcting years of mistakes. Better late than never. Thanks :) – YFl Apr 27 '23 at 17:03
  • Thanks Charles, added this useful comment to my answer – Gilles Quénot Apr 27 '23 at 17:05