2

I have a bash script that is supposed to take some arguments and then run in a different user: test.sh

#!/bin/bash
sudo su user2 <<'EOF'
echo $1
EOF

However it prints blank:

$ ./test.sh haha

I understand that it is because environment variable are reset(?). How can I pass this argument? Security wise I've heard I should not disable environment resetting. The only way comes to my mind to solve this is writing $1 to a file and then reading it back again by user2. But I guess there should be a much better way.

Seperman
  • 123

3 Answers3

9

If you want the entire script to run as another user, my usual technique for doing this is adding something similar to the following to the very top of the script:

target_user="foo"
if [ "$(whoami)" != "$target_user" ]; then
  exec sudo -u "$target_user" -- "$0" "$@"
fi

Note that I use sudo here and not su. su makes it stupidly difficult to pass arguments properly, while sudo does not have this issue.

If you only want to run a small bit of code, you can alternatively do something such as:

target_user="foo"
sudo -u "$target_user" sh -s "$@" <<'EOF'
  echo "$@"
EOF

This will launch sh, pass it the current script's arguments, and then execute the script provided via the heredoc.

phemmer
  • 71,831
  • 1
    your method works pretty well. However I went with the simpler method that G-Man recommended which is not to quote EOF. If you believe your method is for some reason better i.e. security wise or flexibility, I would like to know why please. Thanks – Seperman Sep 19 '14 at 04:45
2

By putting the EOF in quotes, you are effectively quoting the "here document" (echo $1), such that $1 is interpreted by the user2 shell.  But that shell doesn't have any positional parameters.  I can't test these right now, but here are a couple of approaches that might work:

  • Don't quote EOF:

    sudo su user2 << EOF
    echo $1
    EOF
    
  • Pass values through the environment:

    export my_val="$1"
    sudo su user2 << 'EOF'
    echo "$my_val"
    EOF
    
2

This might work :

#!/bin/bash
su - user2 -c 'echo "$0" "$@"' -- "$@"

Use simple quotes ' to pass the command argument to su so you don't have to escape the double quotes ".

References :

Escaping bash function arguments for use by su -c - Stack Overflow

bash - Passing arguments to su-provided shell - Unix & Linux Stack Exchange

Daishi
  • 196