export variable within `/bin/bash -c` [duplicate] - bash

This question already has answers here:
I can't seem to use the Bash "-c" option with arguments after the "-c" option string
(4 answers)
Closed 5 years ago.
I'm trying to export variable within the /bin/bash -c command.
This results in empty output:
/bin/bash -c "export FOO=foo; echo $FOO"
What would be the proper way to do that?

Since you double-quoted the command,
the $FOO got evaluated in your current shell,
not by the /bin/bash -c.
That is, what actually got executed was this:
/bin/bash -c 'export FOO=foo; echo '
Enclose in single-quotes:
/bin/bash -c 'export FOO=foo; echo $FOO'
An equivalent shorter form:
FOO=foo /bin/bash -c 'echo $FOO'

Related

Why getting blank output when running "/bin/sh" with "-c" option [duplicate]

This question already has answers here:
How to use positional parameters with "bash -c" command?
(2 answers)
Closed 14 days ago.
I am running /bin/sh with -c option as below but getting a blank output:
[root#dockerhost dproj]# /bin/sh -c echo helloworld
[root#dockerhost dproj]#
Why the above command is not printing helloworld?
I have tried to read the man page but not able to understand anything.
From man sh:
-c Read commands from the command_string operand.
Set the value of special parameter 0
(see Section 2.5.2, Special Parameters) from the
value of the command_name operand and the positional
parameters ($1, $2, and so on) in sequence from the
remaining argument operands.
No commands shall be read from the standard input.
/bin/sh -c echo helloworld runs the command echo, which prints a blank line. You meant to type:
/bin/sh -c "echo helloworld"
which runs the command echo helloworld.
The -c option to sh causes the first non-option argument to be treated as a string of commands to run in a new shell. The remaining arguments are used to fill in the that shell's numbered arguments, starting with $0 (the "name" under which the shell process is running.) These arguments are not automatically parsed to any utility executed by that shell.
So if you invoke sh with /bin/sh -c echo helloworld:
the input passed to the shell interpreter sh is simply echo
helloworld becomes $0 in the sh session.
Normally, $0 in a shell invocation should be the name of the shell; that's what it will be set to by default:
bash$ /bin/sh
$ echo $0
/bin/sh
$ exit
bash$ echo $0
bash
Since the command given to the shell by -c is interpreted as though it were input to the shell itself, you can use $n in the command in order to refer to the extra arguments to the shell interpreter. If you want to do that, you need to remember to single-quote the -c option argument so that it's contents are not interpreted by the outer shell. Perhaps studying the following will help:
bash$ /bin/sh -c 'echo $0' fakename # Correctly single-quoted
fakename
bash$ /bin/sh -c "echo $0" fakename # Here, $0 is expanded by the outer shell
bash
bash$ /bin/sh -c 'echo "$#"' sh arg1 arg2 arg3 # $0 is not part of $#
arg1 arg2 arg3

Why are my variables not being respected in this ZSH script [duplicate]

This question already has answers here:
Why does a space in a variable assignment give an error in Bash? [duplicate]
(3 answers)
Assigning to a positional parameter [duplicate]
(3 answers)
How do I pass arbitrary arguments to a command executed over SSH? [duplicate]
(1 answer)
Closed 1 year ago.
I have this shell script where I want the CLI inputs to be fed into the SSH command. The first SSH command runs as expected whereas the second has runTests.sh's $1 and $2 set to ''. It seems like it is not substituting them in. Any insights on why that might be?
$1=7107
$2=development
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh 7107 development"'
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh $1 $2"'
You are invoking three different shells: a local shell, a remote login shell, and a remote zsh shell. You need to carefully specify which one should be responsible for which parameter substitutions.
Your variables live in the local shell, but you are asking the remote login shell to expand them. This is why it fails.
Here's how you can have the local shell substitute them instead:
set -- 7107 development # Assign $1 and $2
ssh redacted#redacted -t "zsh -l -c 'source ~/.zshrc && ./runTests.sh $1 $2'"
Since $1 and $2 are now in double quotes in your local shell, they expand, resulting in zsh -l -c 'source ~/.zshrc && ./runTests.sh 7107 development' on the remote side.
This in turn results in source ~/.zshrc && ./runTests.sh 7107 development in the nested zsh shell.
Ideally you'd also want to escape special characters in your data so that values with quotes or spaces work correctly:
ssh redacted#redacted -t "zsh -l -c 'source ~/.zshrc && ./runTests.sh \$1 \$2' _ $(printf %q "$1") $(printf %q "$2")"
$1, $2, $3, ... are reserved to be used as command parameters, for example if you script name is script.sh, when you run:
./script.sh foo bar baz
$1 will be foo, $2 will be bar and $3 will be baz.
Also you should not use spaces when assign.
Try:
foo=7107
bar=development
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh 7107 development"'
ssh redacted#redacted -t 'zsh -l -c "source ~/.zshrc && ./runTests.sh $foo $bar"'
Please note security issues pointed out in comments.

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

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"

Execute command containing quotes from shell variable [duplicate]

This question already has answers here:
Why does shell ignore quoting characters in arguments passed to it through variables? [duplicate]
(3 answers)
Closed 6 years ago.
I'm currently having problems to execute a command from a shell variable.
In general the following works as expected:
COMMAND="echo A"
echo $COMMAND
$COMMAND
produces:
echo A
A
But if I do
COMMAND="su aUser -s /bin/bash -c 'echo A'"
echo $COMMAND
$COMMAND
I get
su aUser -s /bin/bash -c 'echo A'
Password:
A': -c: line 0: unexpected EOF while looking for matching `''
A': -c: line 1: syntax error: unexpected end of file
If I enter the line
su aUser -s /bin/bash -c 'echo A'
directly it works as expected.
It seems my assumption that $COMMAND is equal to entering the content as command directly is wrong.
Questions
1) Does anyone know how I can run the command from a variable?
2) What exactly is the difference between
COMMAND="command"
$COMMAND
and
command
?
Arrays are useful to keep your parameters whole:
command=(su aUser -s /bin/bash -c 'echo A')
and invoke it exactly like this:
"${command[#]}"
You need eval.
$ eval $VARIABLE

Resources