Cannot set environment variable before command - bash

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.

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\""

Command substitution and $PATH variable

Background
This [ article ] says :
The command substitution expands to the output of commands. These
commands are executed in a subshell ..
But the bash manual says nothing about a subshell in its command substitution section.
My test below
$ ps
PID TTY TIME CMD
26483 pts/25 00:00:00 bash
26866 pts/25 00:00:00 ps
$ hpid="$(ps | grep bash)"
$ echo "$hpid"
26483 pts/25 00:00:00 bash
26899 pts/25 00:00:00 bash
shows that a new shell with pid 26899 was spawned during the command substitution. At this point I changed the PATH environment variable.
$ PATH="/some/rogue/path"
did the below stuff :
VAR="$(echo "Do|Die" | cut -d"|" -f 2)"
and got the below error :
Command 'cut' is available in '/usr/bin/cut'
The command could not be located because '/usr/bin' is not included in the PATH environment variable.
cut: command not found
I understand that the error is due to the modification of PATH environment variable which helps the shell locate the binaries. However I am confused when reading this together with command substitution.
If by $(..) a subshell is spawned, then PATH environment variable should be intact and should point to the binary (cut in this case) and so bash should not complain that it cannot locate the cut binary.
Question
How did the modification of the PATH affect the command substitution here?
Consider below example:
$ export PS1='\$\$=$$ \$ '
$$=30862 $ a=123 # Note: No export a here.
$$=30862 $ echo $a
123
$$=30862 $ bash
$$=31133 $ echo $a # Subshell explicitly created does not have it.
$$=31133 $ exit
$$=30862 $ echo $(eval 'echo $a') # This subshell however does inherit it. The single quote ensures that this is not evaluated by parent shell.
123 # echo $(echo $a) would probably cause $a to be evaluated by parent shell.
$$=30862 $
In short, subshells spawned by $(...) inherit same environment as parent shell, even if the variable is not exported. (Even $$ is same as parent shell.)

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

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"

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.

Capistrano 3. To set bash shell on server instead csh

When cap3 try to execute comands on my FreeBSD server - I have an errors and my cap3 tasks doesn't work
DEBUG [0bb99d53] Command: if test ! -d /home/web_server/data/www/capistrano/site/shared/dumps; then echo "Directory does not exist '/home/web_server/data/www/capistrano/site/shared/dumps'" 1>&2; false; fi
DEBUG [0bb99d53] if: Expression Syntax.
DEBUG [0bb99d53] fi: Command not found.
And I know why - because my server use csh shell by default
% echo $0
-csh
Following cap3 variable doesn't work for me
set :shell, '/usr/local/bin/bash'
set :default_shell, '/usr/local/bin/bash'
How can I set shell for cap3 tasks?
You could set the default shell to bash for the deploy user on your server.
chsh -s /usr/local/bin/bash [your_deploy_user]
This worked for me.
My opinion is that you can attempt to use:
/bin/bash -c 'if test ! -d /home/web_server/data/www/capistrano/site/shared/dumps; then echo "Directory does not exist \'/home/web_server/data/www/capistrano/site/shared/dumps\'" 1>&2; false; fi'
From the Bash man page:
If the -c option is present, then commands are read from string. If
there are arguments after the string, they are assigned to the
positional parameters, starting with $0.
I did a test and it worked for me:
1#one:~>%bash -c "/bin/echo Hello; echo Goodbye"
Hello
Goodbye

Resources