46

I'm writing a bash script where I want to exit if the user is not root. The conditional works fine, but the script does not exit.

[[ `id -u` == 0 ]] || (echo "Must be root to run script"; exit)

I've tried using && instead of ; but neither work.

48

You could do that this way:

[[ $(id -u) -eq 0 ]] || { echo >&2 "Must be root to run script"; exit 1; }

("ordinary" conditional expression with an arithmetic binary operator in the first statement), or:

(( $(id -u) == 0 )) || { echo >&2 "Must be root to run script"; exit 1; }

(arithmetic evaluation for the first test).

Notice the change () -> {} - the curly brackets do not spawn a subshell. (Search man bash for "subshell".)

  • 1
    Please exit with a code other than zero, example: exit 1 in order to make understand the parent process that a problem occured. – SamK Nov 4 '11 at 16:32
  • 1
    You shouldn't use [[ for numeric comparison, use ((. – Chris Down Nov 4 '11 at 19:59
  • 1
    @ChrisDown [[ is fine, as long as you use -eq instead of ==. – Let_Me_Be Nov 24 '11 at 10:10
  • Fixed the conditional, added the arithmetic version, @ChrisDown. – Mat Nov 24 '11 at 10:27
  • 2
    @Mat By the way, you can shorten it to (( EUID )) && ... – Chris Down Nov 24 '11 at 11:14
20

The parentheses around those commands creates a subshell. Your subshell echos "Must be root to run script" and then you tell the subshell to exit (although it would've already, since there were no more commands). The easiest way to fix it is probably to just use an if:

if [[ `id -u` != 0 ]]; then
    echo "Must be root to run script"
    exit
fi
  • So there is no way to do this with a one-liner? – Garrett Hall Nov 4 '11 at 15:16
  • 1
    your logic is backwards. in your example, if id -u == 0, which would mean that you are root. You want [[ $(id -u) != 0 ]]; then. – Tim Kennedy Nov 4 '11 at 17:32
  • 4
    If you /must/ have a one-liner, try this on for size: [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1; Also note the $UID, which saves spawning a process. I think you might even prefer $EUID. – janmoesen Nov 4 '11 at 18:19
  • 1
    @janmoesen, good point. And while wee have a variable with a numeric value: ((UID)) && echo 'You have to be root.' && exit 1. – manatwork Nov 4 '11 at 18:25
  • 3
    @janmoesen: note that using such inverse logic will cause a script that set -e to abort. One solution to that problem is [ "$UID" != 0 ] && echo 'You have to be root.' && exit 1 || true. – sam hocevar Nov 4 '11 at 22:14
2

With bash:

[ $UID -ne 0 ] && echo "Must be root to run script" && exit 1
  • That would fail to exit if echo fails (for instance because stdout is not writable). – Stéphane Chazelas Jul 25 '17 at 9:36
1

Brackets around || and && are not required as these are right-associative. The following two expressions are equivalent:

expr1 || expr2 && expr3
expr1 || { expr2 && expr3 }

So && instead of ; would work just fine, as echo will return true.

[[ $(id -u) == 0 ]] || echo "Must be root to run script" && exit 1
  • 1
    While everything you said is correct, this is a bad pattern to learn, because you're relying on the return value of expr2. Are you certain that echo will always return a 0 exit status? It's much better idea to group the statements with curly braces and semi-colons. This is such a common pitfall that it has its own entry in BashPitfalls: mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3 – Flimm Nov 10 '11 at 23:10
  • 1
    @Flimm: I don't agree it's a bad pattern. Evidently, it use is case-dependant, and also depends on your knowledge of the return values you'll get. In this case I'm sure echo will return 0 the 99.999% of times, and if it stomps on a write error (the only case it won't return 0) there's a bigger problem than this expr. There's also the case where YOU are generating the return values, so no, it isn't a "bad pattern" per se for me. – ata Nov 11 '11 at 0:18
  • I'll add too, like it says in the wiki, that you should use it if sure to understand C evaluation. Anyway, a little testing should clear any ambiguities. – ata Nov 11 '11 at 0:26
-1

this might help you , in bash

[oracle@rac1 ~]$ which bash
/bin/bash
[oracle@rac1 ~]$ cat test1.sh
if [ `id -u` != 0 ]
then
echo "Must be root to run the script
 "
exit
fi
  • 3
    This has already been answered and accepted. Also, your answer is near identical to what has already been posted. – maulinglawns Nov 15 '16 at 10:12
  • @maulinglawns, that answer, contrary to the other ones has the merit of being portable to all Bourne-like shells (it would be better if the error was output on stderr, the exit status was non-zero and the command substitution was quoted though) – Stéphane Chazelas Jul 25 '17 at 9:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.