60

Can I change/su user in the middle of a script?

if [ "$user" == "" ]; then
  echo "Enter the table name";
  read user
fi

gunzip *
chown postgres *
su postgres 
dropdb $user
psql -c "create database $user with encoding 'unicode';" -U dbname template1
psql -d $user -f *.sql
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Radek
  • 13,813
  • 52
  • 161
  • 255
  • 1
    possible duplicate of [How do I use su to execute the rest of the bash script as that user?](http://stackoverflow.com/questions/1988249/how-do-i-use-su-to-execute-the-rest-of-the-bash-script-as-that-user) – Ciro Santilli OurBigBook.com May 24 '14 at 06:29

6 Answers6

74

You can, but bash won't run the subsequent commands as postgres. Instead, do:

su postgres -c 'dropdb $user'

The -c flag runs a command as the user (see man su).

38

You can use a here document to embed multiple su commands in your script:

if [ "$user" == "" ]; then
  echo "Enter the table name";
  read user
fi

gunzip *
chown postgres *
su postgres <<EOSU
dropdb $user
psql -c "create database $user with encoding 'unicode';" -U dbname template1
psql -d $user -f *.sql
EOSU
David Braun
  • 5,573
  • 3
  • 36
  • 42
  • Be careful, I think some characters, like backtick, need to be escaped if you put them in a here document. – David Winiecki Apr 09 '15 at 00:59
  • 2
    Also be careful that all variables in the heredoc are substituted *before* passing it to `su`. This can be a problem when you create and use variables inside. To avoid that, turn off parameter substitution by surrounding the first `EOSU` with single quotes, like so: `su postgres <<'EOSU'` – user2009388 Oct 12 '20 at 10:25
  • Note that `==` isn't guaranteed to work inside `[`. The only standard-mandated string comparison operator is `=` – Charles Duffy Jul 07 '21 at 19:19
14

Not like this. su will invoke a process, which defaults to a shell. On the command line, this shell will be interactive, so you can enter commands. In the context of a script, the shell will end right away (because it has nothing to do).

With

su user -c command

command will be executed as user - if the su succeeds, which is generally only the case with password-less users or when running the script as root.

Use sudo for a better and more fine-grained approach.

mvds
  • 45,755
  • 8
  • 102
  • 111
7

Refer to answers in below question,

You can write between << EOF and EOF as mentioned in answers.

#!/bin/bash
whoami
sudo -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami

How do I use su to execute the rest of the bash script as that user?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
4

No you can't. Or atleast... you can su but su will simply open a new shell at that point and when it's done it will continue with the rest of the script.

One way around it is to use su -c 'some command'

Wolph
  • 78,177
  • 11
  • 137
  • 148
2

Another interesting idea that I heard today is to do a recursive call on the script, when you run as root and you want to run the script as another user. See the example below:

I am running script "my_script" as "root" and want the script to run as user "raamee"


#!/bin/bash

#Script name is: my_script

user=`whoami`

if [ "$user" == "root" ]; then
  # As suggested by glenn jackman. Since I don't have anything to run once 
  # switching the user, I can modify the next line to: 
  # exec sudo -u raamee my_script and reuse the same process
  sudo -u raamee my_script
fi

if [ "$user" == "raamee" ]; then
  #put here the commands you want to perform
  do_command_1
  do_command_2
  do_command_3
fi
RaamEE
  • 3,017
  • 4
  • 33
  • 53