Clayton Stanley
Clayton Stanley

Reputation: 7784

Using bash process substitution for a sudo command

I would like to use bash process substitution for a sudo command.

For example, here's a non-sudo command that works for me:

$ cat <(echo "installed.txt")
installed.txt

And here's a sudo version of the command that does not work:

$ sudo cat <(echo "installed.txt")
cat: /dev/fd/63: Bad file descriptor

Reading the sudo man page, it seems that sudo closes all but the stdin/stdout/stderr file descriptors before running the command as root. This leads me to think that bash is creating the descriptor (and performing the process substitution) before running the sudo command.

I changed root's shell to bash (instead of sh default). I've tested that the command works fine when logged in as root. It only does not work via a sudo command.

What is the appropriate technique to achieve what I'm trying to do here? Eval, quoting, sudo flag, sudoers file mod, other?

Upvotes: 15

Views: 4022

Answers (5)

MoonCactus
MoonCactus

Reputation: 1526

In case you're asking for process substitution for the security it brings, like hiding a password from the process list, then you might better do it this way:

cat <(echo -n "$PASSWORD") | sudo cryptsetup ... --key-file -

Sure, the password is sent to sudo through its stdin, so the process substitution is not done within sudo as asked. And my answer becomes technically off topic.

I still hope it will help in this particular context, because the accepted answer comes with serious drawbacks: you need to build a properly quoted string, and then spawn a secondary shell to interpret it within the sudo.

This makes it not only slow, but also risky due to shell injection, environment variables and so.

Upvotes: 2

starfry
starfry

Reputation: 9943

The behaviour described in the question is due to the design of sudo.

$ sudo cat <(echo "installed.txt")
cat: /dev/fd/63: Bad file descriptor

The error occurs because sudo has a default behaviour which closes file descriptors except for standard input, output and error. As described on the man page:

By default, sudo will close all open file descriptors other than standard input, standard output and standard error when executing a command.

This behaviour can be overridden with the -C (or --close-from) option to specify a file descriptor number below which files should not be closed. However, use of this option must be permitted by an administrator: the following needs to be added to /etc/sudoers

 Defaults closefrom_override

With that in place, the command will work if -C is used:

$ sudo -C64 cat <(echo "installed.txt")
installed.txt

(here the number 64 was given because it was greater than the 63 in the error message).

Upvotes: 15

emrys57
emrys57

Reputation: 6806

sudo bash  -c 'cat <(echo "installed.txt")'

Upvotes: 3

Gilles Qu&#233;not
Gilles Qu&#233;not

Reputation: 184965

Try doing this in your shell :

$ sudo bash -c 'cat <(echo "installed.txt for UID=$UID")'
installed.txt for UID=0

Upvotes: 12

gniourf_gniourf
gniourf_gniourf

Reputation: 46813

The best approach is probably to put everything in a script, and run that script with sudo.

Upvotes: 0

Related Questions