Skip to content

Instantly share code, notes, and snippets.

@vjove
Created December 17, 2018 08:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vjove/dc73c02b1858ba8d8494b1b9a8ec2e51 to your computer and use it in GitHub Desktop.
Save vjove/dc73c02b1858ba8d8494b1b9a8ec2e51 to your computer and use it in GitHub Desktop.

BASH Cheat Sheet

Common structures

Sudo

(Extracted from: https://unix.stackexchange.com/questions/175415/forward-function-and-variables-into-sudo-su-user-eof)

sudo -i constructs a pristine environment. Even a plain sudo removes most variables from the environment.
Furthermore sudo is an external command; there's no way to elevate privileges in the shell script itself, only to run an external program (sudo) with extra privileges, and that means any shell variables (i.e. non-exported variables) and functions defined in the parent shell won't be available in the child shell.

You can pass environment variables through by not invoking a login shell (sudo bash instead of sudo su - or sudo -i) and configuring sudo to let these variables through (with Defaults !env_reset or Defaults env_keep=… in the sudoers file).
This won't help you for functions (although bash has a function export facility, sudo blocks it). The normal way to get your functions in the child shell would be to define them there.

Quoting

If you use <<EOF for the here document, the content of the here document is first expanded by the parent shell, and the result of that expansion becomes the script that the child shell sees.
That is, if you write

sudo -u "$target_user" -i <<EOF
  echo "$(whoami)"
EOF

This displays the name of the original user, not the target user.

While you can make use of an unquoted here document marker to pass data from the parent shell to the child shell, this only works if the data doesn't contain any special character.

The output of whoami becomes a bit of shell code, not a string.
For example, if the whoami command returned "; rm -rf /; "true then the child shell would execute the command echo ""; rm -rf /; "true".

To avoid this first phase of expansion, quote the here document marker after the << operator:

sudo -u "$target_user" -i <<'EOF'
  echo "$(whoami)"
EOF

So if you don't need to pass data from the parent shell to the child shell, you can use a quoted here document:

#!/bin/bash
sudo -u "$target_user" -i  <<'EOF'
  log_f() {
    echo "LOG line: $@"
  }
  intVAR=$(date)
  log_f "${intVAR}"
EOF

If you need to pass data from the parent shell, a simple way is to pass it as arguments. Invoke the child shell explicitly and pass it positional parameters:

#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i sh  _ "$extVAR" <<'EOF'
  log_f() {
    echo "LOG line: $@"
  }
  intVAR=$(date)
  log_f "${intVAR}" "${1}"
EOF

If you have multiple variables to pass, it will be more readable to pass them by name. Call env explicitly to set environment variables for the child shell.

#!/bin/bash
extVAR="yourName"
sudo -u "$target_user" -i env extVAR="$extVAR" sh <<'EOF'
  log_f() {
    echo "LOG line: $@"
  }
  intVAR=$(date)
  log_f "${intVAR}" "${1}"
EOF

Note that if you expected /etc/profile and the target user's ~/.profile to be read, you'll have to read them explicitly, or call bash --login instead of sh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment