Linux sudo Command
last modified October 23, 2026
The sudo command runs a command as another user, by default as
root. Instead of sharing the root password, administrators grant individual
users the right to run all or selected commands with elevated privileges.
Users authenticate with their own password, and every command is logged.
The rules are kept in the /etc/sudoers file.
The syntax is sudo [options] command. The examples use sudo
1.9.13 on Debian 12. They were run in interactive terminal sessions by the
user bob, a member of the sudo group, on a host
called box; the users alice, carol,
and deploy have various other rights. Passwords are typed but
not echoed, so they do not appear in the transcripts.
Running a command as root
We put sudo in front of a command to run it with root
privileges.
whoami sudo whoami sudo id
The first sudo asks for bob's own password, not
the root password. The second one does not ask at all, because
sudo remembers a successful authentication for 15 minutes.
Some distributions, such as Fedora, also print a short lecture about
responsible use the first time a user runs sudo; Debian and
Ubuntu build sudo without it.
$ whoami bob $ sudo whoami [sudo] password for bob: root $ sudo id uid=0(root) gid=0(root) groups=0(root)
Who may use sudo
On Debian and Ubuntu, members of the sudo group may run any
command as root; on Fedora, RHEL, and Arch Linux, the group is called
wheel.
id getent group sudo
The id command shows that bob belongs to the
sudo group. To grant a user full administrator rights, we add
them to the group with sudo usermod -aG sudo user; the change
takes effect at the user's next login.
$ id uid=1002(bob) gid=1003(bob) groups=1003(bob),27(sudo) $ getent group sudo sudo:x:27:bob
Credential caching
The cached authentication is valid for one terminal session. A few options manage it.
sudo -v sudo -n true && echo "credentials cached" sudo -k sudo -n true echo $?
The -v option (validate) authenticates and refreshes the cache
without running a command. The -n option (non-interactive)
never asks for a password; when one is needed, sudo fails
instead, which is what scripts and cron jobs need. The -k
option (kill) discards the cached credentials, so the next
sudo asks again. A new terminal window has its own cache, so it
asks for the password too.
$ sudo -v [sudo] password for bob: $ sudo -n true && echo "credentials cached" credentials cached $ sudo -k $ sudo -n true sudo: a password is required $ echo $? 1
Wrong passwords
sudo allows three password attempts.
sudo ls /root
After each wrong password, sudo pauses briefly and asks
again. After the third failure, it gives up, and the failed attempt is
logged. Some distributions enable the insults option, which
replaces the "Sorry, try again" message with a humorous remark.
$ sudo ls /root [sudo] password for bob: Sorry, try again. [sudo] password for bob: Sorry, try again. [sudo] password for bob: sudo: 3 incorrect password attempts
Users without sudo rights
Users who are not mentioned in the sudoers rules cannot use
sudo. Here alice logs in with su and
tries it.
su - alice sudo whoami
sudo asks for the password first, so it cannot be used to probe
the rights of an account without knowing its password. Older versions add "This incident
will be reported." to the message; the attempt is logged either way.
$ su - alice Password: alice@box:~$ sudo whoami [sudo] password for alice: alice is not in the sudoers file. alice@box:~$ exit logout
Listing privileges
The -l option lists what the current user may run;
-U lists the rights of another user, which requires root
privileges.
sudo -l sudo -l -U alice
The output first shows the Defaults settings that apply, and
then the rules. (ALL : ALL) ALL means that bob may
run any command as any user and any group. Checking sudo -l is
the quickest way to find out why a command is refused.
$ sudo -l
[sudo] password for bob:
Matching Defaults entries for bob on box:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty,
logfile=/var/log/sudo.log
User bob may run the following commands on box:
(ALL : ALL) ALL
$ sudo -l -U alice
User alice is not allowed to run sudo on box.
Running commands as another user
The -u option runs the command as a different user, and
-g as a different group.
sudo -u alice whoami sudo -u alice touch /home/alice/notes.txt sudo ls -l /home/alice/notes.txt sudo -g devs id -gn
Files created with sudo -u alice belong to alice,
so this is the right way to work in another user's or a service account's
directory, for example sudo -u postgres psql or
sudo -u www-data php script.php. Creating the file as root
would leave a root-owned file that alice could not modify.
$ sudo -u alice whoami [sudo] password for bob: alice $ sudo -u alice touch /home/alice/notes.txt $ sudo ls -l /home/alice/notes.txt -rw-r--r-- 1 alice alice 0 Oct 23 19:28 /home/alice/notes.txt $ sudo -g devs id -gn devs
Root shells: -s and -i
For a longer administration session, sudo can start a root
shell. The -s option starts a shell, and -i
simulates a full login.
sudo -s sudo -i sudo -i pwd
With -s, the shell stays in the current directory, and the
prompt ends with # to warn us that we are root. With
-i, sudo runs the target user's login shell, which
reads its profile files and changes to its home directory, just as if root
had logged in. With a command, -i runs it in that login
environment. Root shells should be left with exit as soon as
possible; running individual commands with sudo leaves a better
log.
$ sudo -s [sudo] password for bob: root@box:/home/bob/work# whoami; pwd; echo $HOME root /home/bob/work /root root@box:/home/bob/work# exit exit $ sudo -i root@box:~# whoami; pwd; echo $HOME root /root /root root@box:~# exit logout $ sudo -i pwd /root
Repeating a command with sudo
A common situation is a command that fails because it needs root
privileges. In Bash, sudo !! repeats it with
sudo.
cat /var/log/app/app.log sudo !!
!! is Bash history expansion for the previous command. Bash
prints the expanded command before running it. This works only in
interactive shells, not in scripts.
$ cat /var/log/app/app.log cat: /var/log/app/app.log: Permission denied $ sudo !! sudo cat /var/log/app/app.log [sudo] password for bob: 2026-10-23 08:02:05 ERROR payment failed
sudo and redirection
A redirection is performed by our shell, which runs as the normal user,
before sudo even starts.
sudo echo "level=info" > /etc/app.conf echo "level=info" | sudo tee /etc/app.conf echo "port=9090" | sudo tee -a /etc/app.conf > /dev/null sudo sh -c 'echo "workers=4" >> /etc/app.conf' cat /etc/app.conf
The first command fails without asking for a password: bob's
shell cannot open /etc/app.conf for writing, so
sudo never runs. The tee command, run with
sudo, writes its input to the file; -a appends,
and redirecting to /dev/null hides the copy that
tee prints. Alternatively, sudo sh -c runs the
whole command line, redirection included, in a root shell.
$ sudo echo "level=info" > /etc/app.conf bash: /etc/app.conf: Permission denied $ echo "level=info" | sudo tee /etc/app.conf [sudo] password for bob: level=info $ echo "port=9090" | sudo tee -a /etc/app.conf > /dev/null $ sudo sh -c 'echo "workers=4" >> /etc/app.conf' $ cat /etc/app.conf level=info port=9090 workers=4
Environment and PATH
By default, sudo resets the environment (the
env_reset option) and uses a fixed PATH (the
secure_path option). This prevents a user from influencing a
root command through variables.
export PATH=$HOME/bin:$PATH APP_MODE=test hello sudo hello sudo printenv HOME USER SUDO_USER sudo printenv APP_MODE; echo "exit: $?" sudo --preserve-env=APP_MODE printenv APP_MODE sudo APP_MODE=prod printenv APP_MODE sudo "$(command -v hello)"
The hello script is in ~/bin, which is on
bob's PATH but not on the secure path, so
sudo cannot find it; giving the full path works.
HOME and USER are set for root, and
SUDO_USER records who ran sudo, which scripts can
use. Our APP_MODE variable is removed. It can be kept with
--preserve-env=APP_MODE (or all variables with
-E), or set on the sudo command line; both are
allowed only when the sudoers rules permit it, as they do for
ALL.
$ export PATH=$HOME/bin:$PATH APP_MODE=test $ hello hello from bob $ sudo hello [sudo] password for bob: sudo: hello: command not found $ sudo printenv HOME USER SUDO_USER /root root bob $ sudo printenv APP_MODE; echo "exit: $?" exit: 1 $ sudo --preserve-env=APP_MODE printenv APP_MODE test $ sudo APP_MODE=prod printenv APP_MODE prod $ sudo "$(command -v hello)" hello from root
The sudoers file
The rules are stored in /etc/sudoers and in files in the
/etc/sudoers.d directory.
sudo grep -Ev '^(#|$)' /etc/sudoers sudo ls -l /etc/sudoers /etc/sudoers.d
A rule has the form who where=(as_whom) what. The line
%sudo ALL=(ALL:ALL) ALL says that members of the
sudo group (% marks a group), on all hosts, may
run as any user and group any command. Defaults lines set
options. The @includedir directive reads every file in
/etc/sudoers.d whose name contains no dot and does not end with
~. The files are readable only by root. Our lab adds a
logfile setting in 00-logfile.
The sudoers file must never be edited with an ordinary editor. A syntax
error would break sudo for everyone, and on a system without a
root password, nobody could fix it. The visudo command opens a
copy in an editor and checks the syntax before installing it;
sudo visudo -f /etc/sudoers.d/name edits a drop-in file.
$ sudo grep -Ev '^(#|$)' /etc/sudoers [sudo] password for bob: Defaults env_reset Defaults mail_badpass Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" Defaults use_pty root ALL=(ALL:ALL) ALL %sudo ALL=(ALL:ALL) ALL @includedir /etc/sudoers.d $ sudo ls -l /etc/sudoers /etc/sudoers.d -r--r----- 1 root root 1714 Apr 11 2026 /etc/sudoers /etc/sudoers.d: total 8 -r--r----- 1 root root 35 Oct 23 19:27 00-logfile -r--r----- 1 root root 1096 Apr 11 2026 README
Granting specific commands
Rules can be limited to particular commands, given with full paths and
optionally with arguments. Instead of editing interactively, we write a
drop-in file, check it with visudo -c, and install it.
cat carol.sudoers sudo visudo -cf carol.sudoers sudo install -m 0440 carol.sudoers /etc/sudoers.d/carol sudo -l -U carol
The -c option checks the syntax and -f names the
file to check. The install command copies the file with the
mode 0440 that sudo expects. The rule allows
carol to view the application log with tail,
either without options or with -n and a line count.
$ cat carol.sudoers
# carol may read the application log
carol ALL=(root) /usr/bin/tail /var/log/app/app.log, /usr/bin/tail -n * /var/log/app/app.log
$ sudo visudo -cf carol.sudoers
[sudo] password for bob:
carol.sudoers: parsed OK
$ sudo install -m 0440 carol.sudoers /etc/sudoers.d/carol
$ sudo -l -U carol
Matching Defaults entries for carol on box:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty,
logfile=/var/log/sudo.log
User carol may run the following commands on box:
(root) /usr/bin/tail /var/log/app/app.log, /usr/bin/tail -n * /var/log/app/app.log
Testing the rule
Now carol logs in and tries the rule.
sudo tail /var/log/app/app.log sudo cat /var/log/app/app.log sudo tail -n 1 /etc/shadow /var/log/app/app.log
The permitted command works, and cat is refused. The third
command shows a serious mistake in the rule: in sudoers, the
* wildcard in arguments matches anything, including spaces and
additional file names. carol could read
/etc/shadow, which contains password hashes. Wildcards in
command arguments should be avoided; list the exact allowed forms, such as
/usr/bin/tail -n 50 /var/log/app/app.log, instead.
For the same reason, never allow editors, pagers, interpreters, or commands
such as find or tar through sudo
unless full root access is intended; most of them can start a shell or
write arbitrary files.
$ su - carol Password: carol@box:~$ sudo tail /var/log/app/app.log [sudo] password for carol: 2026-10-23 08:02:05 ERROR payment failed carol@box:~$ sudo cat /var/log/app/app.log Sorry, user carol is not allowed to execute '/usr/bin/cat /var/log/app/app.log' as root on box. carol@box:~$ sudo tail -n 1 /etc/shadow /var/log/app/app.log ==> /etc/shadow <== deploy:$y$j9T$FJY0fgPEMQQc1lnNn4TVJ0$wJzksVJUkGW561hv7IGkdyT2Tj3pUwgiLC3Qwi9eLC4:20749:0:99999:7::: ==> /var/log/app/app.log <== 2026-10-23 08:02:05 ERROR payment failed carol@box:~$ exit logout
Syntax errors
visudo -c catches errors before they take effect.
cat deploy.sudoers sed 's/NOPASSWD:/NOPASSWD/' deploy.sudoers > bad.sudoers sudo visudo -cf bad.sudoers sudo visudo -cf deploy.sudoers && sudo install -m 0440 deploy.sudoers /etc/sudoers.d/deploy
We create a broken copy of the rule without the colon after
NOPASSWD. visudo reports the line and column and
exits with a non-zero status, so the && chain installs
a file only after it has passed the check.
$ cat deploy.sudoers
# the deploy account runs the deployment script without a password
deploy ALL=(root) NOPASSWD: /usr/local/bin/deploy.sh
$ sed 's/NOPASSWD:/NOPASSWD/' deploy.sudoers > bad.sudoers
$ sudo visudo -cf bad.sudoers
[sudo] password for bob:
bad.sudoers:2:52: syntax error
deploy ALL=(root) NOPASSWD /usr/local/bin/deploy.sh
^
$ sudo visudo -cf deploy.sudoers && sudo install -m 0440 deploy.sudoers /etc/sudoers.d/deploy
deploy.sudoers: parsed OK
Commands without a password
The NOPASSWD: tag allows commands to run without
authentication. It is typical for service accounts and automation, which
have no one to type a password.
sudo /usr/local/bin/deploy.sh sudo -n whoami
The deploy user runs the deployment script without being asked
for a password. The tag applies only to the listed command; for anything else,
sudo wants a password, and with -n it fails
immediately instead of asking, which is the right option in scripts.
$ su - deploy Password: deploy@box:~$ sudo /usr/local/bin/deploy.sh deploying release as root deploy@box:~$ sudo -n whoami sudo: a password is required deploy@box:~$ exit logout
Aliases and groups
Larger configurations use aliases for lists of users and commands, and
group rules. The team.sudoers file contains the following
rules.
Cmnd_Alias WEB = /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx User_Alias WEBADMINS = alice, carol WEBADMINS ALL=(root) WEB %devs ALL=(alice) NOPASSWD: ALL
Cmnd_Alias names a list of commands and User_Alias
a list of users; alias names are written in capital letters. Members of the
devs group may run any command as alice without a
password.
sudo visudo -cf team.sudoers sudo install -m 0440 team.sudoers /etc/sudoers.d/team sudo -l -U carol | tail -n 4 sudo -l -U jano | tail -n 2
carol now has both her earlier rule and the web commands from
the alias. jano, a member of devs, may act as
alice. Files in /etc/sudoers.d are read in
alphabetical order, and when several rules match, the last one wins.
$ sudo visudo -cf team.sudoers
[sudo] password for bob:
team.sudoers: parsed OK
$ sudo install -m 0440 team.sudoers /etc/sudoers.d/team
$ sudo -l -U carol | tail -n 4
User carol may run the following commands on box:
(root) /usr/bin/tail /var/log/app/app.log, /usr/bin/tail -n * /var/log/app/app.log
(root) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
$ sudo -l -U jano | tail -n 2
User jano may run the following commands on box:
(alice) NOPASSWD: ALL
Editing files with sudoedit
sudoedit (or sudo -e) edits a protected file
without running the editor as root.
ls -l /etc/app.conf export SUDO_EDITOR='sed -i s/9090/8080/' sudoedit /etc/app.conf cat /etc/app.conf
sudoedit copies the file to a temporary file owned by the user,
runs the editor as the user, and copies the result back as root. The
editor is chosen by the SUDO_EDITOR, VISUAL, or
EDITOR variable; here we use sed to make the
change visible in a transcript, but normally it is vim or
nano. Because the editor runs without privileges, its shell
escapes and plugins cannot be abused, so allowing sudoedit
/etc/app.conf in sudoers is safe, unlike allowing vim
/etc/app.conf.
$ ls -l /etc/app.conf -rw-r--r-- 1 root root 31 Oct 23 19:28 /etc/app.conf $ export SUDO_EDITOR='sed -i s/9090/8080/' $ sudoedit /etc/app.conf [sudo] password for bob: $ cat /etc/app.conf level=info port=8080 workers=4
Logging
sudo logs every command to the system log (on systemd
systems, see journalctl _COMM=sudo). Our lab also writes to a
file, set with Defaults logfile=/var/log/sudo.log.
sudo tail -n 6 /var/log/sudo.log
Each entry records the time, the user, the terminal, the working directory,
the target user, and the full command. The sudoedit entry shows
the editor command that was run.
$ sudo tail -n 6 /var/log/sudo.log
[sudo] password for bob:
Oct 23 19:29:41 : bob : TTY=pts/0 ; PWD=/home/bob/work ; USER=root ;
COMMAND=/usr/bin/install -m 0440 team.sudoers /etc/sudoers.d/team
Oct 23 19:29:47 : bob : TTY=pts/0 ; PWD=/home/bob/work ; USER=root ;
COMMAND=/usr/bin/sed -i s/9090/8080/ -- /etc/app.conf
Oct 23 19:29:51 : bob : TTY=pts/0 ; PWD=/home/bob/work ; USER=root ;
COMMAND=/usr/bin/tail -n 6 /var/log/sudo.log
Best practices for sudo
- Use sudo for single commands: Avoid long root shells; individual commands are logged and make mistakes less likely.
- Grant the least privilege: Allow specific commands
with full paths instead of
ALLwhere possible. - Avoid wildcards and shell escapes: Do not allow
*in arguments, editors, pagers, or interpreters; usesudoeditfor editing. - Always use visudo: Check every change with
visudo -cand keep drop-in files in/etc/sudoers.dwith mode 0440. - Use -n in scripts: Scripts should fail rather than hang at a password prompt.
- Mind redirection: Write protected files with
sudo teeorsudo sh -c.
Source
In this article, we have used the sudo command to run commands
as root and as other users, managed cached credentials, worked around the
redirection pitfall, and written, checked, and tested sudoers rules. See
also the passwd and
file permissions articles.
Author
List all Linux tutorials.