32

I want to run one of the two commands C1 and C2 at random. How do I do that on commandline (bash)? Will appreciate if a one-liner is possible.

Anthon
  • 78,313
  • 42
  • 165
  • 222
user13107
  • 5,265
  • 10
  • 45
  • 62

3 Answers3

39
if (( RANDOM % 2 )); then C1; else C2; fi
Chris Down
  • 122,090
  • 24
  • 265
  • 262
  • 2
    Bear in mind that if you want a 1 in N odds of running C1, you must probably use `(( RANDOM % N == 0 ))` rather than `(( RANDOM % N ))`. It's only the in special case of N=2 that these have identical probability. – Asclepius Jul 08 '15 at 03:25
  • 2
    Plainly put, of what practical use would be `RANDOM % $N` without `== 0`? IMO, for example with N=100, it is much more pragmatic to want a 1 in 100 odds (delivered with `== 0`) than a 99 in 100 odds (delivered without `== 0`). – Asclepius Jul 08 '15 at 20:41
21

In your special case:

C$((RANDOM%2+1))

will work :) And hey, it's the shortest answer!

gniourf_gniourf
  • 1,499
  • 8
  • 13
6

You can do something like this in Bash:

$ (( RANDOM%2 == 0 )) && C1 || C2

This will generate a random number, either 0 or 1. If it's a 0, then C1 runs, otherwise C2 runs if it isn't.

example

$ (( RANDOM%2 == 0 )) && echo 0 || echo 1
1

$ (( RANDOM%2 == 0 )) && echo 0 || echo 1
0

NOTE: The first character, $, is the prompt.

another example

If you're concerned with C1 having to fail so that C2 can run you could restructure the above like so:

(( RANDOM%2 == 0 )) && CMD=C1 || CMD=C2
$CMD

why use this over a if/then statement?

This answer has been criticized a bit but there's a method to my madness. Though this pattern may seem more obscure than a if/then I find it more readable and compact when doing something like the following:

#!/bin/bash
CMD=""
DIRS="/etc /home /www /data1 /data2 /var/log /var/spool/mail"
FILE="/backup/$(hostname)-$(date +'%m-%d-%y').tar.gz"
[ "$1" == "nas" ]  && CMD="lftp -u user,password -e 'cd /dump/; mput /backup/*; quit' nas.mylan.com" || :
[ "$1" == "scp" ]  && CMD="scp /backup/* scponly@dumpserver:incoming' username" || :
[ "$1" == "tape" ] && CMD='tar -cf /dev/st0 /backup/*' || :
[ "$CMD" == "" ]   && exit 1 || :
# make a backup
tar -zcvf  $FILE $DIRS
# Now depend upon circumstances run a backup command
$CMD

References

slm
  • 363,520
  • 117
  • 767
  • 871
  • 2
    This will run `C2` if `C1` fails, which violates the specification laid out in the question (namely, that only *one* of the commands is run). `x && y || z` is not equivalent to `if x; then y; else z; fi`. – Chris Down Jul 03 '13 at 04:34
  • @ChrisDown - see mods. – slm Jul 03 '13 at 04:48
  • 4
    The edit nominally fixes this, but it's really obscure. "If you're concerned with C1 having to fail so that C2 can run" doesn't capture the scenario at all. The issue is that if `C1` is a command which sometimes returns a non-zero exit code, you will end up executing both `C1` and `C2` when that happens. – tripleee Jul 03 '13 at 06:23
  • +1 but use `((...))` instead of `[...]` -- double parentheses are specifically for arithmetic expressions. – glenn jackman Jul 03 '13 at 09:45
  • @glennjackman - thanks I've made the change. – slm Jul 03 '13 at 11:57
  • One more simplification: you don't need `$(())` inside `(())` -- `(( RANDOM%2 == 0 ))` – glenn jackman Jul 03 '13 at 11:59
  • @glennjackman - I see what you were suggesting now. Thanks. I've fixed it. – slm Jul 03 '13 at 12:01