434

I'm writing a script that requires root level permissions, and I want to make it so that if the script is not run as root, it simply echoes "Please run as root." and exits.

Here's some pseudocode for what I'm looking for:

if (whoami != root)
  then echo "Please run as root"

  else (do stuff)
fi

exit

How could I best (cleanly and securely) accomplish this? Thanks!

Ah, just to clarify: the (do stuff) part would involve running commands that in-and-of themselves require root. So running it as a normal user would just come up with an error. This is just meant to cleanly run a script that requires root commands, without using sudo inside the script, I'm just looking for some syntactic sugar.

Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
Nathan
  • 73,987
  • 14
  • 40
  • 69
  • 12
    (1) make it not executable by anything else then root (2) arrange further permissions as well.. (3) `id -u` returns `0` for root. – Wrikken Aug 13 '13 at 17:59

23 Answers23

619

The $EUID environment variable holds the current user's UID. Root's UID is 0. Use something like this in your script:

if [ "$EUID" -ne 0 ]
  then echo "Please run as root"
  exit
fi

Note: If you get 2: [: Illegal number: check if you have #!/bin/sh at the top and change it to #!/bin/bash.

sashoalm
  • 75,001
  • 122
  • 434
  • 781
ptierno
  • 9,534
  • 2
  • 23
  • 35
  • It seems that good permissions and having this is a double layer of security – Kellen Stuart Nov 15 '16 at 20:02
  • 50
    I think is better to compare string with string, number with number. using double brackets, you could use > directly with no quotation [[ $EUID > 0 ]] – Sergio Abreu Jan 03 '17 at 02:29
  • 9
    I got `2: [: Illegal number:` warning until changed it to Sergio's version. – alexeydemin Jan 12 '17 at 03:16
  • 2
    The problem with this is that if you use `sudo`, `$EUID` does not change. So if a script is run with `sudo`, this check would incorrectly complain that it doesn't have root privileges (which is what you actually want - you don't have to _be_ root). – Stephen Angelico Apr 30 '18 at 12:58
  • You're missing a semicolon after the closing bracket! – thekiwi5000 Feb 09 '19 at 18:22
  • 2
    @thekiwi5000 The semicolon is only required if the `then` is on the same line as the condition... – ptierno Feb 11 '19 at 16:19
  • 3
    @StephenAngelico Sudo should work. If you're testing it by doing $ sudo echo $EUID ; that's a bad test and will fail because $EUID is expanded before the command is passed to sudo. Try putting echo $EUID in a test script and running that with sudo. – user1169420 Feb 18 '19 at 03:49
  • 5
    `$EUID` doesn't work in `dash` (a common `/bin/sh` implementation). – marcelm Nov 15 '20 at 09:14
  • Alternatively : `if (($EUID))`. Props to `ormaaj` and `gnoo` from `#bash` on `irc.libera.chat` – ychaouche Jun 12 '22 at 12:20
  • Is it `bash` of vanilla `shell`? – Sandburg Jun 17 '22 at 10:16
  • @StephenAngelico `sudo bash -c 'echo "$EUID"'` shows 0 on bash version 5.1.4(1) and sudo version 1.9.5p2. Please add a reproducer that shows a scenario where `sudo` does not change the euid! – Luc Jul 19 '23 at 13:01
  • @Luc Same bash and sudo versions: `echo $EUID -> 1000`, `sudo echo $EUID -> 1000` – Stephen Angelico Jul 20 '23 at 03:27
  • @Luc I concede your point though, your command is more equivalent to running a script. In a terminal, $EUID is unchanged when running a process with sudo, whereas in a script, the environment in created from root ownership. – Stephen Angelico Jul 20 '23 at 03:38
177

A few answers have been given, but it appears that the best method is to use is:

  • id -u
  • If run as root, will return an id of 0.

This appears to be more reliable than the other methods, and it seems that it return an id of 0 even if the script is run through sudo.

Nathan
  • 73,987
  • 14
  • 40
  • 69
  • Except if there's no "root" but you still have necessary privileges. Short correct answer is - use it for cosmetic purposes only. – AnrDaemon Feb 01 '22 at 16:36
  • This solution also works in sh and dash, but `id` is not a shell built-in the way that `$EUID` is in bash and zsh: it requires having coreutils installed (which is a common enough assumption, so that seems okay to me). This command and flag also work on FreeBSD but I'm not sure how to check if this was part of a package installation. – Luc Jul 19 '23 at 13:06
101

In a bash script, you have several ways to check if the running user is root.

As a warning, do not check if a user is root by using the root username. Nothing guarantees that the user with ID 0 is called root. It's a very strong convention that is broadly followed but anybody could rename the superuser another name.

I think the best way when using bash is to use $EUID, from the man page:

EUID   Expands to the effective user ID of the current  user,  initialized
       at shell startup.  This variable is readonly.

This is a better way than $UID which could be changed and not reflect the real user running the script.

if (( $EUID != 0 )); then
    echo "Please run as root"
    exit
fi

A way I approach that kind of problem is by injecting sudo in my commands when not run as root. Here is an example:

SUDO=''
if (( $EUID != 0 )); then
    SUDO='sudo'
fi
$SUDO a_command

This ways my command is run by root when using the superuser or by sudo when run by a regular user.

If your script is always to be run by root, simply set the rights accordingly (0500).

Matthew Rapati
  • 5,648
  • 4
  • 28
  • 48
sberder
  • 4,505
  • 2
  • 26
  • 15
  • If the person who is trying to run the script does not have sudo privileges, this will cause the error to be thrown and the command will not run? Just want to make sure, I understand correctly. – Caperneoignis Apr 07 '16 at 14:15
  • 2
    I am not sure this answer is 100% completely correct. On RHEL7.2 using Bash 4.2.46... if I `printf $EUID` with or without sudo, I get my own UID back. If I use `id -u` I get my UID and when I invoke it with sudo I get 0 back. Did I do something wrong? – 0xSheepdog Jul 21 '16 at 19:53
  • 6
    @0xSheepdog, it's possible that on the bash cli, the $EUID variable expansion gets resolved first, then sudo changes user. Therefore you would get that behavior, but in scripts, everything would still work fine. – Alexander Bird Aug 04 '16 at 19:06
  • @AlexanderBird Good point, thank you! I did not do any real testing, just reported my experience. – 0xSheepdog Aug 06 '16 at 13:49
  • 4
    Use a "herestring" for your test to prevent local shell expansion of the variable. Compare `sudo bash <<<'echo $EUID'` to `bash <<<'echo $EUID'`. More about the heredoc-like herestring at http://tldp.org/LDP/abs/html/x17837.html – Bruno Bronosky Jan 20 '17 at 22:04
97

My one-liner:

if [ "$(id -u)" -ne 0 ]; then echo "Please run as root." >&2; exit 1; fi
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
Dale_Reagan
  • 1,953
  • 14
  • 11
  • 1
    You could consider integrating [Jeremy J Starcher's answer](http://stackoverflow.com/a/18216143/1504300) with this part, in the end it's always the same stuff... – reallynice Aug 25 '14 at 13:26
  • I know that from the terminal, when I forget to prefix something with `sudo` I can simply type `sudo !!` and it does the work for me, rather than pressing the UP arrow, going to the beginning of the line, and adding `sudo ` by hand. Not sure if that is a BASH thing or a SUDO thing or other, but it works most all of the time. – 0xSheepdog Jul 19 '16 at 21:08
  • @0xSheepdog: It's a Bash thing (and a feature of some other shells such as csh, where IIRC it originated). – Dennis Williamson Aug 26 '16 at 16:12
47

In this answer, let it be clear, I presume the reader is able to understand the difference betweeen modern shells like bash, zsh and others vs portable POSIX shells like dash.

I believe there is not much to explain here since the highly voted answers do a good job of explaining much of it.

Yet, if there is anything to explain further, don't hesitate to comment, I will do my best by filling the gaps.


Optimized all-round solution for performance and reliability; all shells compatible

New solution:

# bool function to test if the user is root or not
is_user_root () { [ "${EUID:-$(id -u)}" -eq 0 ]; }

Benchmark (save to file is_user_root__benchmark)

#+------------------------------------------------------------------------------+
#|                           is_user_root() benchmark                           |
#|                  "Bash is fast while Dash is slow in this"                   |
#|                          Language: POSIX shell script                        |
#|                     Copyright: 2020-2021 Vlastimil Burian                    |
#|                      M@il: info[..]vlastimilburian[..]cz                     |
#|                               License: GPL 3.0                               |
#|                                 Version: 1.2                                 |
#+------------------------------------------------------------------------------+

readonly iterations=10000

# intentionally, the file does not have an executable bit, nor it has a shebang
# to use it, just call the file directly with your shell interpreter like:

# bash is_user_root__benchmark    ## should take a fraction of one second
# dash is_user_root__benchmark    ## could take around 10 seconds

is_user_root () { [ "${EUID:-$(id -u)}" -eq 0 ]; }

print_time   () { date +"%T.%2N"; }
print_start  () { printf '%s' 'Start  : '; print_time; }
print_finish () { printf '%s' 'Finish : '; print_time; }

printf '%s\n' '___is_user_root()___'; print_start
                   
i=1; while [ "$i" -lt "$iterations" ]; do
    is_user_root
    i=$((i+1))
done; print_finish

Examples of use and duration:

$ dash is_user_root__benchmark 
___is_user_root()___
Start  : 03:14:04.81
Finish : 03:14:13.29

$ bash is_user_root__benchmark 
___is_user_root()___
Start  : 03:16:22.90
Finish : 03:16:23.08

Explanation

Since it is multitude times faster to read the $EUID standard bash variable, the effective user ID number, than executing id -u command to POSIX-ly find the user ID, this solution combines both into a nicely packed function. If, and only if, the $EUID is for any reason not available, the id -u command will get executed, ensuring we get the proper return value no matter the circumstances.


Why I post this solution after so many years the OP has asked

Well, if I see correctly, there does seem to be a missing piece of code above.

You see, there are many variables which have to be taken into account, and one of them is combining performance and reliability.


Portable pure POSIX solution + Example of usage of the above function

#!/bin/sh

# bool function to test if the user is root or not (POSIX only)
is_user_root ()
{
    [ "$(id -u)" -eq 0 ]
}

if is_user_root; then
    echo 'You are the almighty root!'
    # You can do whatever you need...
else
    echo 'You are just an ordinary user.' >&2
    exit 1
fi

Conclusion

As much as you possibly don't like it, the Unix / Linux environment has diversified a lot. Meaning there are people who like bash, zsh, and other modern shells so much, they don't even think of portability (POSIX). It is nowadays a matter of personal choice and needs.

Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
  • You could use POSIX substitution `${EUID:=$(id -u)}` to achieve near-perfect performance match in case of repetitive execution of the same test. – AnrDaemon Feb 01 '22 at 16:34
  • @AnrDaemon Hello, I've just tried it, and it's working as expected. Did you down-vote because of it? I saw 1 down just after you commented, just did not have time to respond until now. Sorry about that. Anyway, thanks for teaching me just another expansion. :) I will think about it, and maybe change the whole thing... Cheers – Vlastimil Burián Feb 09 '22 at 21:56
  • No, I downvoted because it is principally impossible to test for permissions based on user's name/id alone. See [my comment](https://stackoverflow.com/questions/18215973/how-to-check-if-running-as-root-in-a-bash-script/52586842?noredirect=1#comment125415762_28776100) below. – AnrDaemon Feb 10 '22 at 06:49
  • @AnrDaemon Do you have any proof on EUID or id -u being whatever you want to call it .. e.g imperfect? – Vlastimil Burián Feb 10 '22 at 07:06
  • It is not imperfect, it merely does what it is designed for. But does not make any claims other than what it says. $EUID MAY BE 0, but that doesn't mean you have rights to do anything you pleased (fakeroot f.e.), the reverse is also true - you may not be EUID=0 but have the necessary permissions (Cygwin, there's no UID=0 by design). – AnrDaemon Feb 10 '22 at 14:48
38

There is a simple check for the user being root.

# Fancy red-colored `error` function with `stderr` redirection with `exit`.
error ()
{
    { printf '\E[31m'; echo "$@"; printf '\E[0m'; } >&2
    exit 1
}

# Test for root user.
if [ "$EUID" -eq 0 ]; then
    error "Do not run this as the root user"
fi

This also assumes that you want to exit with a 1 if you fail. The error function is some flair that sets output text to red (not needed, but pretty classy if you ask me).

Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
Slater Victoroff
  • 21,376
  • 21
  • 85
  • 144
  • Oh, that's just a small flair thing. Doesn't matter all that much, but I'll attach it. – Slater Victoroff Aug 13 '13 at 20:09
  • 4
    That's pretty cool! If I may suggest a few improvements: (1) move the newline to the end; (2) write to standard error rather than standard output; (3) only set the color if standard error is a terminal (rather than risk writing escape characters into log-files or `less` or whatnot); and (4) set a background-color, so the text will be readable regardless of the background-color of the user's terminal. So, something like `function error () { if [[ -t 2 ]] ; then echo $'\033[31;2;47m'"$@"$'\033[0m' ; else echo "$@" ; fi >&2 ; }`. (Tweak as desired.) – ruakh Aug 13 '13 at 20:38
  • 4
    Shouldn't that be "-ne" instead of "-eq"? – Carlos Rendon Mar 17 '14 at 16:17
  • 2
    @CarlosRendon Slater's code is to *prevent* something from being run as root. (This is opposite what the OP was asking for, but the method of checking would be the same.) – Joshua Taylor Sep 30 '14 at 19:26
30

As @wrikken mentioned in his comments, id -u is a much better check for root.

In addition, with proper use of sudo, you could have the script check and see if it is running as root. If not, have it recall itself via sudo and then run with root permissions.

Depending on what the script does, another option may be to set up a sudo entry for whatever specialized commands the script may need.

Jeremy J Starcher
  • 23,369
  • 6
  • 54
  • 74
14

1- Read official GNU Linux documentation, there are many ways to do it correctly.

2- make sure you put the shell signature to avoid errors in interpretation:

#!/bin/bash

3- this is my script

#!/bin/bash 

if [[ $EUID > 0 ]]; then  
  echo "Please run as root/sudo"
  exit 1
else
  #do your stuff
fi
Sergio Abreu
  • 2,686
  • 25
  • 20
11

Very simple way just put:

if [ "$(whoami)" = "root" ]; then
    # you are root
else
    # you are not root
fi

The benefit of using this instead of id is that you can check whether a certain non-root user is running the command, too; eg.

if [ "$(whoami)" = "john" ]; then
    # you are john
else
    # you are not john
fi

Editor's Note: Either prefer using POSIX-compatible test command and comparison [... = ...] or you can use Bash/+other shells specific [[... == ...]].

Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
Matthew Trotter
  • 167
  • 1
  • 2
  • if you test the user with a string "root", aren't you allowing to run anyone that is named "root"? – pcarvalho Oct 21 '15 at 18:15
  • 3
    +1 for actually answering the question about `whoami` rather than using `id`; the `whoami` command can also be used to check for *other* users than root, by name. – Jez Aug 22 '16 at 10:26
7

One simple way to make the script only runnable by root is to start the script with shebang:

#!/bin/su root
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
alexandre1985
  • 1,056
  • 3
  • 13
  • 31
  • 1
    I'm curious why this answer isn't voted higher? It seems like the simplest and cleanest. Are there disadvantages here? – Bassinator Sep 10 '18 at 21:14
  • @Bassinator I believe some people say it won't run on certain nix's but it has work flawlessly on my Linux so far. Try it! Maybe this answer has come late to the race but I'm trying to add knowleadge that is simple to the community (instead of giving similiar answers, like most on this thread :/ ) Vote this up if you are lucky to read this and it works on your machine – alexandre1985 May 19 '19 at 22:38
  • @TamusJRoyce If the goal is checking if you are running as a root and not forcing the script to run only as root, why is then in every answer , after the check if is running as root, they make the script `exit`? And still those answers are being upvoted? I guess people implicitly do not want the script to be run as root. So I'm following that way of thinking, with a simpler answer. But yeah, you can also learn from the more verbose answers above – alexandre1985 May 25 '19 at 11:15
  • @alexandre1985 Exactly. Scenario: If running as root, maybe you want a script to default to installing the program globally when it asks how you want it installed. Otherwise, the default is set to install it locally. Instead of hitting enter, the user could choose to install it global or local. But if they like the default, they can hit enter. And they will not be prompted with a password. Your shebang will never "check" if you are root (per title). But I still think this answer is useful. – TamusJRoyce May 25 '19 at 16:35
  • @TamusJRoyce totally makes sense your comment. Indeed is a concern and this solution is not for that use case. You opened my perspectives. You are right. Thanks – alexandre1985 May 26 '19 at 18:45
  • 1
    Doesn't work in my `bash` (`GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu) `). – basickarl Jan 29 '20 at 12:21
  • @KarlMorrison Just tested and still works in mine `GNU bash, versão 5.0.11(1)-release (x86_64-pc-linux-gnu)` – alexandre1985 Jan 30 '20 at 13:07
  • Doesn't work because I disabled root login and some Linux distros disable root login. – Jack G Jul 14 '20 at 12:59
  • A couple of disadvantages I can see, main issue is you need to know root's password, presumably this relies on the shell specified in /etc/passwd, it may behave strangely if the shell and script are not both bash. su and su - are not the same thing trick hardcodes not using a login shell. It will cd if you do use a login shell and fail. – teknopaul Apr 11 '21 at 07:33
  • Which password is needed is not indicated to the user, Unlike sudo password is not remembered. There is an extra fork compared to checking $EUID. forks even if you are already root. Unlike use of sudo the script executed is not logged. Its a cool trick but not necessarily obvious when reading the script, and like other shebang tricks it does not work if run bash -x ./script and will only fail when root is needed compared to other answers here that have an else clause to the check and fail fast. – teknopaul Apr 11 '21 at 07:41
  • also if you run this script from another program and and want to send signals, (e.g. kill -9 if it takes too long) it wont work as expected. – teknopaul Apr 11 '21 at 07:43
  • this doesn't work for some reason always says auth failure with the same password I use to run sudo su. – Brad Mar 13 '22 at 08:46
  • @Brad Your problem may be with the su command. Try checking your PAM configuration – alexandre1985 Apr 01 '22 at 10:33
5

If the script really requires root access then its file permissions should reflect that. Having a root script executable by non-root users would be a red flag. I encourage you not to control access with an if check.

chown root:root script.sh
chmod u=rwx,go=r script.sh
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 4
    If someone has their permissions in order this works great, but I feel like overuse of the `777` bomb makes this check a little faulty for the kind of users that would make the mistake in the first place. – Slater Victoroff Aug 13 '13 at 18:08
  • 9
    This is assuming the user is running an executable script. If the user just calls `bash /path/to/script` it can still be ran even though `o=r` – ptierno Nov 14 '14 at 21:26
5

Try the following code:

#!/bin/sh

if [ "$(id -u)" -ne 0 ]; then
    echo "Sorry, you are not root." >&2
    exit 1
fi

Note on edit: Backticks are considered deprecated by now (many further notes).

Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
MLSC
  • 5,872
  • 8
  • 55
  • 89
3

id -u is much better than whoami, since some systems like Android may not provide the word root.


Example command:

# whoami

Example output:

whoami: unknown uid 0
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
Smeterlink
  • 716
  • 6
  • 20
3

As far as I know, the correct way to check it, is as follows:

#!/bin/sh

if [ "$(id -u)" -eq 0 ]; then
    echo "You are root."
else
    echo "You are NOT root." >&2
fi

OP's Note: you may see "Testing For Root" section on linuxcommand.org.

Editor's Note: I have slightly adjusted this shell snippet to be POSIX-compatible.

Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
WebBrother
  • 1,447
  • 20
  • 31
3

The problem using: id -u, $EUID and whoami, is all of them give false positive when I fake the root, like this:

$ fakeroot

id:

$ id -u
0

$EUID:

$ echo $EUID
0

whoami:

$ whoami
root

Then a reliable (and hacking) way is verify if the user has access to the /root directory:

$ ls /root >/dev/null 2>&1 && is_root=true || is_root=false; echo "$is_root"
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
Sr. Libre
  • 339
  • 4
  • 10
  • 1
    Checking for `/root/` folder access may also give false positive when access rights to the folder are altered. – user7860670 Jan 23 '22 at 09:25
  • I understand that /root DIR is only accessible by root, of course if root user change permission you can access but this is not a common case. – Sr. Libre Feb 08 '22 at 21:32
  • What is the advantage in thwarting fakeroot usage? The user is clearly annoyed by the check and tries to circumvent it. A system call down the line will error out if they don't have sufficient privileges, or maybe they set capabilities or run in a different environment, so you might as well let them try it. – Luc Jul 19 '23 at 13:18
  • @Luc this is an uncommon scenario but suppose you have script wrapper to compile something from source code and you want to avoid download, configure and make commands for this specific task for standard user. – Sr. Libre Jul 19 '23 at 15:44
3

It is important to notice that whenever you run a script using sudo the 'user context' or environment will switch to root.

But Teo what that means?

Well, my young padawan, this means that if a padawan user runs a script that contains a tilde (~) using sudo, whenever the bash will expand ~ the result will be /root and not /home/<user> (i.e., in this case /home/padawan), or if you create either a directory or a file the owner and group will be root and not the that executed the script in this case padawan, because the user environment was switched.

For instance, lets check this script install-app.sh:

#!/bin/bash
ROOT_UID=0   # Only users with $UID 0 have root privileges.
E_NOTROOT=87 # Non-root exit error.

## Prevent the execution of the script if the user has no root privileges
if [ "${UID:-$(id -u)}" -ne "$ROOT_UID" ]; then
    echo 'Error: root privileges are needed to run this script'
    exit $E_NOTROOT
fi
...
mkdir -vp ~/app/init
touch config
...
touch /home/<user>/app/init/profile
service mysql start
...

If we run using sudo:

sudo install-app.sh

This will create directories and a config file will look like this:

##
## ~ (/root)
drwxr-xr-x 17 root root    4096 Nov 23 20:45 ./
drwxr-xr-x  5 root root    4096 Nov 15 19:04 ../
...
drwxr-xr-x  3 root root    4096 Nov 25 14:30 app/
...
drwxr-xr-x  2 root root    4096 Nov 16 19:08 tmp/

## ~/app (/root/app)
drwxr-xr-x  3 root root 4096 Nov 25 14:30 ./
drwxr-xr-x 17 root root 4096 Nov 25 14:33 ../
drwxr-xr-x  2 root root 4096 Nov 25 14:33 init/

## ~/app/init (/root/app/init)
drwxr-xr-x 2 root root 4096 Nov 25 14:33 ./
drwxr-xr-x 3 root root 4096 Nov 25 14:30 ../
-rw-r--r-- 1 root root    0 Nov 25 14:33 config

## /home/<user>/app/conf
drwxr-xr-x 2 <user> <user> 4096 Nov 25 14:43 ./
drwxr-xr-x 3 <user> <user> 4096 Nov 25 14:30 ../
-rw-r--r-- 1 root   root      0 Nov 25 14:43 profile

As you can see the script is a total mess. Now the <user> cannot get access to the profile file, nor can they modify the config without using sudo. At the beginning, this may seem not important, but I assure you that if your project gets bigger, someone will run the script and mess with your system.

Recommendation:

Prompt the user to verify if they are a sudoer. Then, add sudo to the commands that require it.

The following code shows how to apply these changes to the script:

#!/bin/bash
E_NOTROOT=87 # Non-root exit error.

## Prevent the execution of the script if the user has no root privileges
## Check if is sudoer
if ! $(sudo -l &>/dev/null); then
    echo 'Error: root privileges are needed to run this script'
    exit $E_NOTROOT
fi
...
mkdir -vp ~/app/init
touch config
...
touch /home/<user>/app/init/profile
sudo service mysql start
...

This modification allows the user to run the script like this:

install-app.sh

The user will be requested to insert his password to verify if is sudoer. After,mkdir -vp ~/app/init will create the file in the user's home:

/home/<user>/app/init
/home/<user>/app/init/config
/home/<user>/app/init/profile

Also, I recommend to get the users homer directory and use it as a constant.

## Defines user home directory
USER_HOME_DIR=$(getent passwd ${SUDO_USER:-$USER} | cut -d: -f6)
...
mkdir -vp "$USER_HOME_DIR/app/init"
...
Teocci
  • 7,189
  • 1
  • 50
  • 48
2
#!/usr/bin/env sh
[ "`id -u`" -ne 0 ] && echo "Please run me as root!"

Unlike all other answers, this script:

  1. Does not depend on anything being named "root", such as the user name or a /root directory.

  2. Is compatible with and tested on:

    Only "fish" is a shell that is not compatible (there seems to be no way to have compatibility between the more commons shells above and fish).

  3. Works on:

    • Linux with coreutils installed (even a minimal Debian, Ubuntu, etc. will have this)
    • FreeBSD
    • Android (based on Smeterlink's answer)

    I'd be interested if anyone has a macOS or Windows Linux Subsystem machine to test this on as well! Please comment or edit this answer.

  4. Detects:

    • sudo (tested version: 1.9.5p2)
    • doas (tested version: 6.8.1-2)
    • real root (switched user using su + password)

    Fakeroot is not detected, but if the user wants to pretend they're root, I see no reason to not let them.

Luc
  • 5,339
  • 2
  • 48
  • 48
1

Check if you are root and quit if you are not:

if ((EUID != 0)); then
    echo "Root or Sudo  Required for script ( $(basename $0) )"
    exit
fi

Or in this example, try to create a directory in root location then try after rights were elevated.

Check if you are root and if not elevate if possible :

# Fails to create these dirs (needs sudo)
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)

if ((EUID != 0)); then
    echo "Granting root privileges for script ( $(basename $0) )"
    if [[ -t 1 ]]; then
        sudo "$0" "$@"
    else
        exec 1> output_file
        gksu "$0" "$@"
    fi
    exit
fi
echo "Root privileges granted..."
# Creates Dirs as it now has rights
mkdir /test-dir-$(basename $0)
rmdir /test-dir-$(basename $0)
Mike Q
  • 6,716
  • 5
  • 55
  • 62
0

I stumbled on the same issue. The line #!/bin/su root would be an elegant method, but does not work on certain (higher) versions of bash, as mentioned by @basickarl. Further - this method will probably fail when you start the script with /bin/bash ./some_script.(b)sh.

I found an other page on SO where the use of the environment variables SUDO_UID and SUDO_USER were used. When a normal user invokes a script with sudo these are available in the script. Otherwise they are empty. Also: when you are actually logged on as root these values are empty (or unset - not entirely sure) as well.

So this is the solution I'm currently using:

isSudo()
{
  local _fn="${FUNCNAME[0]}"
  if [[ $(/usr/bin/id -u) -eq 0 ]] ; then
    if [[ ! -z "$SUDO_UID" && ! -z "$SUDO_USER" ]] ; then
      >2 echo -e "$_fn: invoked as sudo-user ($SUDO_USER)."
    else
      >2 echo -e "$_fn: invoked as root ($SUDO_USER)."
    fi
    return 0
  fi
  >2 echo "$_fn: not as root or as sudoer."
  return 1
}

Then use it like this eg.:

if $(isSudo) ; then
  echo -e "Script started as root or as sudoer."
else
  echo -e "Script not started as root or with sudo"
fi

The >2 in front of the echo is to redirect the echo to stderr otherwise the if statement goes haywire and it's just for a little debugging. In stead of using an echo, you could save "root", "sudoer" or "user" in a local variable and let the function echo that back and then perform a case on that like this:

how_invoked()
{
  local _invoked_as="USER"
  if [[ $(/usr/bin/id -u) -eq 0 ]] ; then
    if [[ ! -z "$SUDO_UID" && ! -z "$SUDO_USER" ]] ; then
      _invoked_as="SUDOER"
    else
      _invoked_as="ROOT"
    fi
  fi
  echo -n "$_invoked_as" # -n prevents newline
}

And then use it like this:

INVOKED_AS=$(how_invoked)
case $INVOKED_AS in
  USER)
    echo -e "Invoked as user." ;;
  SUDOER)
    echo -e "Invoked as sudoer." ;;
  ROOT)
    echo -e "Invoked as root." ;;
  *)
    echo -e "I'm confused" ;;
esac

Or if you just want to test for one of those:

if [ "$(how_invoked)" == "SUDOER" ] ; then
  echo -e "You are a sudoer."
else
  echo -e "You are NOT a sudoer."
fi

Hope this helps.

sjoerd
  • 47
  • 5
0

I don't really think UID-based answers are any good here.

There can be privileged users, that where UID != 0, there can also be systems where uid or other commands are not available.

Most of the time the best solution seems to me to just try the command without root, and then do it again with root privileges or run a command that 100% requires root and to something if it fails with a permissions error.

con-f-use
  • 3,772
  • 5
  • 39
  • 60
-1

My two cents, running in Bash:

#!/bin/bash

# Display the UID variable
echo "Your UID is $UID"

# Check for root user via UID
if [ "$UID" -eq 0 ]; then
    echo "You are root"
else
    echo "You are not root user" >&2
fi
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52
Pramod Kharade
  • 2,005
  • 1
  • 22
  • 41
-1

My one-liner:

[ "$(whoami)" != root ] && echo "Please, run as root." >&2 && exit 1

Tested under Debian, Ubuntu and Docker.

Contango
  • 76,540
  • 58
  • 260
  • 305
-2

My check for the root user, running in Bash:

#!/bin/bash

if [ "$UID" -eq 0 ]; then
    echo "You are root."
else
    echo "You are just an ordinary user." >&2
fi
Vlastimil Burián
  • 3,024
  • 2
  • 31
  • 52