Echo variable using sudo bash -c 'echo $myVariable' - bash script - bash

I want to echo a string into the /etc/hosts file. The string is stored in a variable called $myString.
When I run the following code the echo is empty:
finalString="Hello\nWorld"
sudo bash -c 'echo -e "$finalString"'
What am I doing wrong?

You're not exporting the variable into the environment so that it can be picked up by subprocesses.
You haven't told sudo to preserve the environment.
\
finalString="Hello\nWorld"
export finalString
sudo -E bash -c 'echo -e "$finalString"'
Alternatively, you can have the current shell substitute instead:
finalString="Hello\nWorld"
sudo bash -c 'echo -e "'"$finalString"'"'

You can do this:
bash -c "echo -e '$finalString'"
i.e using double quote to pass argument to the subshell, thus the variable ($finalString) is expanded (by the current shell) as expected.
Though I would recommend not using the -e flag with echo. Instead you can just do:
finalString="Hello
World"

Related

Using /bin/bash -l -c with concatenated commands does not pass environment variables

I'm trying to execute a series of bash commands using /bin/bash -l -c as follows:
/bin/bash -l -c "cmd1 && cmd2 && cmd3..."
What I notice is that if cmd1 happens to export an environment variable, it is not seen by cmd2 and so on. If I run the same concatenated commands without the /bin/bash -l -c option, it just runs fine.
For example, this does not print the value of MYVAR:
$/bin/bash -l -c "export MYVAR="myvar" && echo $MYVAR"
whereas, the following works as expected
$export MYVAR="myvar" && echo $MYVAR
myvar
Can't find why using /bin/bash -l -c won't work here? Or are there any suggestion how to make this work with using /bin/bash -l -c?
variables are exported for child processes, parent process environment can't be changed by child process so consecutive commands (forking sub processes can't see variables exported from preceeding command), some commands are particular becuase don't fork new process but are run inside current shell process they are builtin commands only builtin commands can change current process environment export is a builtin, for more information about builtins man bash /^shell builtin.
Otherwise expansion is done during command parsing:
/bin/bash -l -c "export MYVAR="myvar" && echo $MYVAR"
is one command (note the nested quotes are not doing what you expect because are closing and opening quoted string, myvar is not quoted and may be split). So $MYVAR is expanded to current value before assigned to myvar.
export MYVAR="myvar" && echo $MYVAR
are two commands and $MYVAR because && is bash syntax (not literal like "&&"), is expanded after being assigned.
so that $ have a literal meaning (not expanded) use single quotes or escape with backslash.
/bin/bash -l -c 'export MYVAR="myvar" && echo "$MYVAR"'
or
/bin/bash -l -c "export MYVAR=\"myvar\" && echo \"\$MYVAR\""

How can a Bash variable be used in a string passed to Bash?

Let's say I've got the following here-document (which is used to enable hibernation in Ubuntu):
IFS= read -d '' text << "EOF"
[Re-enable hibernate by default in upower]
Identity=unix-user:*
Action=org.freedesktop.upower.hibernate
ResultActive=yes
[Re-enable hibernate by default in logind]
Identity=unix-user:*
Action=org.freedesktop.login1.hibernate
ResultActive=yes
EOF
I could store this text in a protected file in a way like the following:
echo "${text}" | sudo tee /etc/polkit-1/localauthority/50-local.d/com.ubuntu.enable-hibernate.pkla
How could I do a similar operation using the Bash variable in a command string (that's using the redirect operator) passed to Bash running under root?
sudo bash -c 'echo "${text}" > /etc/polkit-1/localauthority/50-local.d/com.ubuntu.enable-hibernate.pkla'
In the new instance of Bash, the variable obviously doesn't exist.
One option would be to pass the variable as an argument, like this:
sudo bash -c 'printf "%s\n" "$0" > /path/to/output' "$text"
text variable is no more defined in the new bash environment, that is why it is failing.
This below command has been tested ok, give it a try:
sudo bash -c 'cat > /etc/polkit-1/localauthority/50-local.d/com.ubuntu.enable-hibernate.pkla' <<<"${text}"

where did my environment variable go?

I am trying to use an environment variable in a bash script that needs to run as sudo with source.
I have the following file (my_file.sh)
echo "this is DOMAIN = $DOMAIN"
I have the DOMAIN environment variable in my session..
and now I need to run
sudo -E bash -c "source ./my_file.sh"
but the output does not display the value for $DOMAIN. instead it is empty.
if I change the command to be
sudo -E bash -c "echo $DOMAIN"
I see the correct value..
what am I doing wrong?
With the command line:
sudo -E bash -c "source ./my_file.sh"
you are running a script that may refer to environment variables that would need to be exported from a parent shell to be visible.
On the other hand:
sudo -E bash -c "echo $DOMAIN"
expands the value of $DOMAIN in the parent shell, not inside your sudo line.
To demonstrate this, try your "working" solution with single quotes:
sudo -E bash -c 'echo $DOMAIN'
And to make things go, try exporting the variable:
export DOMAIN
sudo -E bash -c "source ./my_file.sh"
Or alternately, pass $DOMAIN on the command line:
sudo -E bash -c "source ./my_file.sh $DOMAIN"
And have your script refer to $1.

Cannot set environment variable before command

I am trying to set a variable before calling a command in bash (on Mac):
BRANCH=test echo "$BRANCH"
But I get an empty echo.
printenv also has no other variable with the same name:
$ printenv | grep BRANCH
$
What am I doing wrong?
This is correct way:
BRANCH='test' bash -c 'echo "$BRANCH"'
test
To execute echo command you'll need bash -c to execute it after assignment.

Why is this bash variable empty when I just set it?

$ sudo sh -c "FOO=bar echo Result:${FOO}"
Result:
Why is the value stored in FOO not displayed?
Because bash replaces ${FOO} before calling sudo. So what sh -c actually sees is:
FOO=bar echo Result:
Besides, even if you tried
FOO=bar echo Result:${FOO}
It still won't work1. To get that right, you can do:
FOO=bar; echo Result:${FOO}
Now that that is fixed, let's get back to sh -c. To prevent bash from interpreting the string you are giving to sh -c, simply put it in ' instead of ":
sudo sh -c 'FOO=bar; echo Result:${FOO}'
1 Refer to the comments for reason.
This doesn't work, because the variable FOO is set for the following command, echo, but the ${FOO} is replaced by the enclosing shell.
If you want it to work, you must set the variable FOO for the enclosing shell and wrap the echo ... in single quotes
sudo FOO=bar sh -c 'echo Result:${FOO}'

Resources