Sometimes a command installed with Homebrew needs to be executed as root. A good example is nethogs, which needs elevated privileges to inspect network traffic.
The problem is that this often fails:
|
1 2 |
sudo nethogs |
even though this works:
|
1 2 |
nethogs |
The reason is that sudo usually runs with a different, restricted PATH. Your normal shell can find Homebrew commands, but sudo may not know where Homebrew installed them.
On Linux, Homebrew commands may live somewhere like:
|
1 2 3 |
/home/linuxbrew/.linuxbrew/bin /home/linuxbrew/.linuxbrew/sbin |
On macOS, they are commonly under:
|
1 2 |
/opt/homebrew |
on Apple Silicon, or:
|
1 2 |
/usr/local |
on Intel Macs.
The simple one-command solution
A quick workaround is to resolve the command path before calling sudo:
|
1 2 |
sudo "$(which nethogs)" |
This works because which nethogs is evaluated by your normal shell, using your normal PATH, before sudo runs.
So instead of asking sudo to find nethogs, you give it the full path directly.
A shell function for one command
You can wrap that in a function:
|
1 2 3 |
nethogs() { sudo "$(which nethogs)" "$@" } |
This lets you run:
|
1 2 3 4 |
nethogs nethogs eth0 nethogs -d 5 |
and still preserve arguments correctly.
A general brew-sudo helper
A better cross-platform approach is to define a small helper that asks Homebrew for its prefix, checks both bin and sbin, and then runs the matching executable with sudo.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
brew-sudo() { if [ "$#" -eq 0 ]; then echo "usage: brew-sudo <command> [args...]" >&2 return 2 fi cmd="$1" shift prefix="$(brew --prefix)" || return for dir in bin sbin; do exe="$prefix/$dir/$cmd" if [ -x "$exe" ]; then sudo "$exe" "$@" return $? fi done echo "brew-sudo: $cmd not found in $prefix/bin or $prefix/sbin" >&2 return 127 } |
Now you can run Homebrew-installed commands with root privileges like this:
|
1 2 3 4 |
brew-sudo nethogs brew-sudo nethogs eth0 brew-sudo some-command --some-option |
This works across Linux and macOS because brew --prefix returns the correct Homebrew prefix for the current system.
Defining command-specific wrappers
You can then define convenient wrappers in terms of brew-sudo:
|
1 2 3 |
nethogs() { brew-sudo nethogs "$@" } |
This gives you the best of both worlds:
|
1 2 3 4 |
nethogs nethogs eth0 nethogs -d 5 |
while internally resolving to something like:
|
1 2 |
sudo /home/linuxbrew/.linuxbrew/sbin/nethogs "$@" |
on Linux, or the corresponding Homebrew path on macOS.
Full version
Put this in a shell file sourced by both bash and zsh, or copy it into both ~/.bashrc and ~/.zshrc:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
brew-sudo() { if [ "$#" -eq 0 ]; then echo "usage: brew-sudo <command> [args...]" >&2 return 2 fi cmd="$1" shift prefix="$(brew --prefix)" || return for dir in bin sbin; do exe="$prefix/$dir/$cmd" if [ -x "$exe" ]; then sudo "$exe" "$@" return $? fi done echo "brew-sudo: $cmd not found in $prefix/bin or $prefix/sbin" >&2 return 127 } nethogs() { brew-sudo nethogs "$@" } |
A note on sudo and Homebrew
This approach does NOT run brew itself with sudo. It only uses brew --prefix to locate Homebrew’s installation directory, then runs a specific Homebrew-installed executable with sudo.
That distinction matters: running brew install or brew upgrade with sudo is generally the wrong approach, but running a tool like nethogs with sudo is appropriate when the tool itself needs root privileges.
Alternative: adding Homebrew to /etc/sudoers
Another possible solution is to teach sudo about Homebrew’s executable directories.
On many systems, sudo uses a restricted path configured in /etc/sudoers, often through a setting called secure_path. You can inspect and edit it with:
|
1 2 |
sudo visudo |
You may see a line like this:
|
1 2 |
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
One could add Homebrew’s bin and sbin directories there. For example, on Linuxbrew:
|
1 2 |
Defaults secure_path="/home/linuxbrew/.linuxbrew/sbin:/home/linuxbrew/.linuxbrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
Or on Apple Silicon macOS:
|
1 2 |
Defaults secure_path="/opt/homebrew/sbin:/opt/homebrew/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" |
After that, this may work directly:
|
1 2 |
sudo nethogs |
However, this approach has a security tradeoff.
It does not give users new sudo permissions by itself. A user still needs to be allowed to run commands with sudo in the first place. But it does make Homebrew-installed commands part of sudo’s command lookup path.
That can be undesirable because Homebrew prefixes are often writable by the normal user, or by users in an admin group. In general, root’s PATH should avoid directories that non-root users can modify. Otherwise, it becomes easier to run a user-controlled executable as root accidentally.
For that reason, I prefer the wrapper approach shown above.



















































































































