Escape apostrophe in docker command - bash

I`m trying to add variable using docker CLI command in following way:
docker exec -u root airflowdags_webserver_1 bash -c "airflow variables --set my_var '{\"test\": \"test\'2\"}'"
But getting following error:
bash: -c: line 0: unexpected EOF while looking for matching `"'
bash: -c: line 1: syntax error: unexpected end of file
I have no any errors if doing one of these commands:
docker exec -u root airflowdags_webserver_1 bash -c "airflow variables --set my_var '{\"test\": \"test\`2\"}'"
or
docker exec -u root airflowdags_webserver_1 bash -c "airflow variables --set my_var '{\"test\": \"test2\"}'"
How can I escape apostrophe in the "test'2" value to avoid the error?

A bash single quoted string cannot contain a single quote. You can't escape it. (ref
https://www.gnu.org/software/bash/manual/bashref.html#Single-Quotes)
Try this:
bash -c "airflow variables --set my_var '{\"test\": \"test'\''2\"}'"
# .......................................1.................1..2....2
I numbered the matching single quoted strings. In between is a literal single quote.

With version 3 you can specify an array of commands.
https://docs.docker.com/compose/compose-file/#command

You can use $ before the first single quote to be able to use escaped single quotes in the command.
So:
docker exec -u root airflowdags_webserver_1 bash -c "airflow variables --set my_var $'{\"test\": \"test\'2\"}'"

Related

Unable to execute ssh command containing parentheses with perl: "syntax error near unexpected token `('"

If I run this command from the command line, it works as expected on the remote server:
ssh admin#example.com "docker exec -it -d tasks_live_work_ec2_test_server /bin/sh -c \"/usr/bin/nvim -c 'silent! call SetupInstantServer()'\""
However, if I try to execute it from a perl script, I get errors:
my $cmd = qq|docker exec -it -d ${image_name}_server /bin/sh -c \"/usr/bin/nvim -c 'silent! call SetupInstantServer()'\"|;
`ssh admin\#example.com "$cmd"`;
bash: -c: line 1: syntax error near unexpected token '('`
Escaping the parens with backslashes suppresses the error, but the SetupInstantServer function in vim never gets called.
What I would do, using 2 here-doc:
#!/usr/bin/perl
system<<PerlEOF;
ssh admin\#example.com<<ShellEOF
docker exec -it -d ${image_name}_server /bin/sh -c "
/usr/bin/nvim -c 'silent! call SetupInstantServer()'
"
ShellEOF
PerlEOF
You can decide to add quotes on a 'HereDoc' to prevent shell expansion or the need to escape #. Up to your needs.
Check perldoc perlop#Quote-and-Quote-like-Operators

How do I pass multiple arguments to a shell script into `kubectl exec`?

Consider the following shell script, where POD is set to the name of a K8 pod.
kubectl exec -it $POD -c messenger -- bash -c "echo '$#'"
When I run this script with one argument, it works fine.
hq6:bot hqin$ ./Test.sh x
x
When I run it with two arguments, it blows up.
hq6:bot hqin$ ./Test.sh x y
y': -c: line 0: unexpected EOF while looking for matching `''
y': -c: line 1: syntax error: unexpected end of file
I suspect that something is wrong with how the arguments are passed.
How might I fix this so that arguments are expanded literally by my shell and then passed in as literals to the bash running in kubectl exec?
Note that removing the single quotes results in an output of x only.
Note also that I need the bash -c so I can eventually pass in file redirection: https://stackoverflow.com/a/49189635/391161.
I managed to work around this with the following solution:
kubectl exec -it $POD -c messenger -- bash -c "echo $*"
This appears to have the additional benefit that I can do internal redirects.
./Test.sh x y '> /tmp/X'
You're going to want something like this:
kubectl exec POD -c CONTAINER -- sh -c 'echo "$#"' -- "$#"
With this syntax, the command we're running inside the container is echo "$#". We then take the local value of "$#" and pass that as parameters to the remote shell, thus setting $# in the remote shell.
On my local system:
bash-5.0$ ./Test.sh hello
hello
bash-5.0$ ./Test.sh hello world
hello world

Bash: execute a command with quotes and put its output into a variable

In a bash script I set a command this way:
getdblist_cmd=(sudo -u $backup_user $psql -p $pgsql_port -U $pgsql_user -d postgres -q -t -c 'SELECT datname from pg_database')
Then I run it with
dblist=`${getdblist_cmd[#]}`
I don't get any error into the bash script but the $dblist variable is empty.
How can I execute that command and put its output into a variable?
dblist=`"${getdblist_cmd[#]}"`
^ ^
The [#] operator works only correct if the ${...} is surrounded by quotes.

Executing 'bash -c' in 'docker exec' command

Context: I'm trying to write a shortcut for my daily use of the docker exec command. For some reasons, I'm experimenting the problem that my output is sometimes broken when I'm using a bash console inside a container (history messed up, lines overwrite each other as I'm writing, ...)
I read here that you could overcome this problem by adding some command before starting the bash console.
Here is a relevant excerpt of what my script does
#!/bin/bash
containerHash=$1
commandToRun='bash -c "stty cols $COLUMNS rows $LINES && bash -l"'
finalCommand="winpty docker exec -it $containerHash $commandToRun"
echo $finalCommand
$finalCommand
Here is the output I get:
winpty docker exec -it 0b63a bash -c "stty cols $COLUMNS rows $LINES && bash -l"
cols: -c: line 0: unexpected EOF while looking for matching `"'
cols: -c: line 1: syntax error: unexpected end of file
I read here that this had to do with parsing and expansion. However, I can't use a function or an eval command (or at least I didn't succeed in making it work).
If I execute the first output line directly in my terminal, it works without trouble.
How can I overcome this problem?
It's not Docker related, but Bash (In other words, the docker's part of the command works well, it's just bash grumbling on the container like it would grumble on your host):
Minimal reproducible error
cmd='bash -c "echo hello"'
$cmd
hello": -c: line 0: unexpected EOF while looking for matching `"'
hello": -c: line 1: syntax error: unexpected end of file
Fix
cmd='bash -c "echo hello"'
eval $cmd
hello
Answer
foo='docker exec -it XXX bash -c "echo hello"'
eval $foo
This will let you execute your command echo hello on your container, now if you want to add dynamic variables to this command (like echo $string) you just have to get rid of single quotes for double ones, to make this works you will have to escape inner double quotes:
foo="docker exec -it $container bash -c \"echo $variable\""
A complete example
FOO="Hello"
container=$1
bar=$2
cmd="bash -c \"echo $FOO, $bar\""
final_cmd="docker exec -it $container $cmd"
echo "running command: \"$final_cmd\""
eval $final_cmd
Let's take time to dig in,
$FOO is a static variable, in our case it works exactly like a regular variable, just to show you.
$bar is a dynamic variable which takes second command line argument as value
Because $cmd and $final_cmd uses only double quotes, variables are interpreted
Because we use eval $final_cmd command is well interpreted, bash is happy.
Finally, a usage example:
bash /tmp/dockerize.sh 5b02ab015730 world
Gives
running command: "docker exec -it 5b02ab015730 bash -c "echo Hello, world""
Hello, world

parenthesis in a directory name in bash script

I get the error executing bash syntax error near unexpected token `('
I know the error is caused by the ')' but I thought placing the commands in-between ' ' is suppose to allow the parenthesis in a directory name. How can I fix this without renaming the name?
bash -c 'cd /tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.0000
0sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg) && exec bash xfade.sh'
please note:
It's being called from inside octave a math program like matlab
Why are you bothering with an outer shell? Quote the argument to cd:
(cd '/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg)' && exec bash xfade.sh)
If you really must use an extra bash -c...
dirname='/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg)'
bash -c 'cd "$1" && exec bash xfade.sh' _ "$dirname"
Can you use double quotes for bash -c?
bash -c "cd '/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg)' && exec bash xfade.sh"
You need to quote the path inside of the command string passed to the bash subshell. E.g.:
bash -c 'cd '"'"'/tmp/h1/clients/04212015142432811_Fs_1000_ahh/pls/03sox_a_Fs_1000_ahh_(000_bit)_(0.00000sig_in_deg)_to_(508_bit)_(30.00000sig_in_deg) && exec bash xfade.sh'"'"''
You get the error because running bash -c passes the argument string to a new shell. The argument string will have the single quotes stripped by the outer (invoking) shell.
UPDATED: to correctly quote single quotes inside single quotes as pointed out by Charles Duffy

Resources