2

I want to run some script over powers of two in parallel. Doing so by giving GNU Parallel a list of the powers of two I want works well:

%>parallel echo {} ::: 32, 64, 128, 256, 512, 1024
32
64
128
256
512
1024
%>

I can also give GNU Parallel a range of values without issue:

%>parallel echo {} ::: {5..10}
5
6
7
8
9
10
%>

But once I include the bit of arithmetic in the GNU Parallel command, I am met with a syntax error:

%>parallel echo $((2**{})) ::: {5..10}
bash: 2**{}: syntax error: operand expected (error token is "{}")
%>

This surprises me because I can generate these values in a for loop as so:

%>for N in {5..10}; do echo $((2**N)); done
32
64
128
256
512
1024
%>

What is the way to do this using GNU Parallel? I am not concerned with order.

1
  • I think --dry-run would have helped you figure out what was going on. I recommend using --dry-run every time GNU Parallel does something unexpected.
    – Ole Tange
    Commented Jul 26, 2023 at 9:42

2 Answers 2

1

You need to quote the entire command being run by parallel, for example:

$ parallel 'echo $((2**{}))' ::: {5..10}
32
64
128
256
512
1024

Actually, just quoting the bash arithmetic part of the command works too:

$ parallel echo '$((2**{}))' ::: {5..10}
32
64
128
256
512
1024

The reason is that without quotes, bash will try to expand & evaluate the arithmetic before passing it to parallel, and 2**{} doesn't mean anything to bash. The error message is actually from bash, not parallel:

$ echo $((2**{}))
-bash: 2**{}: syntax error: operand expected (error token is "{}")
1
  • Thank you for pointing that out. I had read that parallel quotes for you but I realize that's not what it meant now.
    – Will
    Commented Jul 26, 2023 at 5:16
1

@cas shows how to use the shell. Personally I like to do it using a {= perl =} replacement string:

parallel echo '{= $_=2**$_ =}' ::: {5..10}

but the difference is tiny and more just a matter of taste.

There are situations, where the Perl version is better: If you for some reason is forced to use a shell which does not have the $(( expression )) construct (e.g. fish) or need more computational functionality: parallel echo '{= $_=2**($_/2) =}'

3
  • $(( .. )) itself is POSIX, so it's likely to be supported in any sensible sh. Exponention with ** isn't standard, though, and e.g. Dash indeed doesn't support it.
    – ilkkachu
    Commented Jul 26, 2023 at 11:44
  • @ilkkachu also, at least my bash doesn't let me do anything but integer math, whereas my zsh does $(( 3.1416 ** 0.5 )) (it also does **, and logical ^^; I think that's it for missing features from bash, but I do have to say, not being able to do floating point math hurts.) Commented Jul 26, 2023 at 19:45
  • 1
    @MarcusMüller, Yes, floating point math also isn't standard, and Bash doesn't support it. It's no surprise zsh is more featureful, and ksh also supports floats, but that's one of the things Bash hasn't copied off the two. I'm not saying there's no reason to use Perl over a shell here, just that $(( ... )) not being available in a POSIX sh isn't one.
    – ilkkachu
    Commented Jul 26, 2023 at 21:36

You must log in to answer this question.

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