Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have a bash script that uses sudo a few times. There's a couple of strange points about it though.

  1. It asks me for my password a few seconds after I've already entered it for a previous command.
  2. The second time I enter my password, it's echoed to the display.

Here's the relevant bits of the script.

sudo service apache2 stop
drush sql-dump --root="$SITE_DIR" --structure-tables-key=svn --ordered-dump | grep -iv 'dump completed on' | sudo tee "$DB_DIR/${SITE_NAME}.sql" > /dev/null
sudo svn diff "$DB_DIR" | less
sudo svn commit -m "$MESSAGE" "$DB_DIR"
sudo service apache2 start

The first password is to stop apache, and it works as expected. As mentioned, the sudo tee doesn't 'remember' that I have elevated privileges, asks for the password again, and echoes it to the screen. Given that tee is all about echoing to screen, I've played around a little with simple scripts which have | sudo tee, and they all work as expected.

Edit: I looked into the drush command itself, and it's a bash file that calls PHP using exec. This sounds like it might have potential - any ideas? Here's the line from drush.

exec php $SCRIPT_PATH --php=`which php` "$@"

Edit2: Was looking up something to do with Ruby scripts and came across this post about elevated privileges in scripts from serverfault.

share|improve this question
    
I can't imagine drush is too smart (Drupal Shell). Put echos in your script so you can see where in the script you get asked. –  Nerdling Jun 18 '10 at 10:51
    
I'm getting asked after the service stop, but before the diff, so it's got to be the sudo tee... is that what you meant? –  Andy Jun 18 '10 at 11:45
add comment

4 Answers

May I suggest another solution? Stop using sudo in bash scripts, instead run the whole script with elevated rights.

You can easily check if the script is run as root or not:

if [[ $(/usr/bin/id -u) -ne 0 ]]; then
    echo "$0 must be run as root"
    exit 1
fi

Taken from this SO question.

share|improve this answer
    
I've only shown part of the script - there are other bits that don't need root privilege, and I'd prefer not to grant it to them. I could factor out the commands above into a separate script and sudo the whole script, but it seems a bit 'over-engineery' to me. –  Andy Jun 18 '10 at 11:42
1  
There's a difference between "over-engineery" and "works" ;) The script in the OP read to me as bad form, in particular because the separate sudo invocations are counting on a side effect (temporary storage of authentication) which shouldn't be counted upon. A script less all the sudo calls could be run by root or by crond, which can't be said of the OP script. –  msw Jun 18 '10 at 11:45
    
:) yeah, it'll work, but it seems to me that I'm scotch-taping the issue. If I don't understand why it's happening this time, I'm sure it'll crop up again. If I factor out some code I prefer it to be because I consider it a discrete reusable chunk - not because it's the only way I can get it to work though I don't know why;) –  Andy Jun 18 '10 at 11:49
    
@msw The script doesn't 'count on' storing the authentication. It will still work fine if it isn't stored. I'm just bemused as to why in this case it isn't stored. Sorry, don't understand the last sentence - could you elaborate please? –  Andy Jun 18 '10 at 11:58
    
That should be if /usr/bin/id -u > /dev/null 2>&1 - no need for the square brackets and -ne 0 –  Dennis Williamson Jun 18 '10 at 14:32
show 2 more comments

Can you recheck your sudo version?
I see this in the current sudo manual,

-A

Normally, if sudo requires a password, it will read it from the current terminal. If the -A (askpass) option is specified, a (possibly graphical) helper program is executed to read the user's password and output the password to the standard output. If the SUDO_ASKPASS environment variable is set, it specifies the path to the helper program. Otherwise, the value specified by the askpass option in sudoers(5) is used.

and,

SUDO_ASKPASS

Specifies the path to a helper program used to read the password if no terminal is available or if the -A option is specified.

Can't recall having read or used this before...

share|improve this answer
    
v 1.7.2p1 It's strange that it should have a problem only the second time, not the first, third, etc. –  Andy Jun 18 '10 at 11:45
add comment

From man 8 sudo examples:

To make a usage listing of the directories in the /home partition. Note that this runs the commands in a sub-shell to make the cd and file redirection work.

$ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE"

And I don't know what "tests" you ran with tee, but the simple case:

$ sudo id | sudo tee /tmp/junk

Prompts for two passwords at once and then they both fight over the input queue so neither one accepts the password (and they screw up the stty line discipline so the typed characters are echoed).

Update: Oh, you wanted to know why the sudo doesn't apply to the pipeline? Because the shell has to fork off the subprocesses of a pipeline each which inherits the context of the parent shell. As far as the shell is concerned, sudo is just a command and it runs its arguments in a context of elevated privilege which does not "flow" down the pipe. As a set of commands the pipeline can be read as

drush sql-dump > pipe ;  ( grep < pipe  ;  ( sudo tee file < pipe ) )

which is a more accurate model of what is happening.

share|improve this answer
    
For me your second example shows the fighting for input, but it doesn't echo the pass. Note I never have a command quite like that one; one example I used was sudo service ; ls | sudo tee output - works fine. –  Andy Jun 18 '10 at 11:55
    
I understand why sudo doesn't apply to the pipeline, which is why I'm using sudo tee instead of normal redirection. What I don't understand is why it doesn't remember the entered password, and why it echoes the characters to screen. –  Andy Jun 18 '10 at 12:11
add comment

You can also always look at something simple like creating a fifo or 'pipe' for output you want to read

`mkfifo -m 600 /path/to/fifo` 

man mkfifo for more info. Your code will now read something like:

sudo service apache2 stop 
#this will be visible and you can type in your password
stty -echo
# this will now remove echoing of characters to the screen
drush sql-dump --root="$SITE_DIR" --structure-tables-key=svn --ordered-dump | grep -iv 'dump completed on' | sudo tee "$DB_DIR/${SITE_NAME}.sql" > /dev/null
# as you are again looking for visible output, i would use the fifo here
sudo svn diff "$DB_DIR" \> /path/to/fifo &
sleep 4 # or longer
tail /path/to/fifo
sudo svn commit -m "$MESSAGE" "$DB_DIR"
sudo service apache2 start
stty echo
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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