0

In my script there's:

#!/bin/bash

# Take sudo password from the first argument if present
SUDO="sudo -u postgres"
if [ "$1" != "" ]; then
    SUDO="echo $1 | sudo -S -u postgres"
fi

${SUDO} psql -c "create database foo;"

... several other similar commands here ...

When I run the script with myPassword I get:

myPassword | sudo -S -u postgres psql -c create database foo;

So it just echoes the line. Obviously what I want is to literally run that command, but so that $1 gets expanded:

$ echo myPassword | sudo -S -u postgres psql -c create database foo;

How can I do that?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
juzzlin
  • 45,029
  • 5
  • 38
  • 50
  • Ideally, you should just configure `sudo` to allow the appropriate uses to run `psql` as the user `postgres` without entering a password. – chepner May 20 '20 at 15:11

1 Answers1

3

Pipes |, redirection < and stuff like that are not interpreted by the shell when you run a command by expanding a variable. Only words are split and globs (*, ?, []) are expanded. Example:

$ v='echo a | cat'
$ $v
a | cat > b

To interpret them, you could use eval

$ v='echo a | cat'
$ eval "$v"
a

However, this is frowned upon as you often end up with quoting issues. Usually, there are better ways to solve a specific problem.

As a somewhat cleaner solution you could wrap your pipe inside a function:

#!/bin/bash

# Take sudo password from the first argument if present
SUDO="sudo -u postgres"
if [ "$1" != "" ]; then
    pw="$1"
    sudoWithPw() { echo "$pw" | sudo -S -u postgres "$@"; }
    SUDO="sudoWithPw"
fi

${SUDO} psql -c "create database foo;"

An even better solution would be to login as user postgres only once instead of prefixing every command with ${SUDO}. You can do so using su or sudo bash -c aFunctionYouExportedEarlier.

Socowi
  • 25,550
  • 3
  • 32
  • 54