Bash alias with nested quotations - bash

how can I set up an alias for this command? (because it has multiple quotations)
rsync -azv -e 'ssh -o "ProxyCommand ssh -A some#place -W %h:%p"' user#xxx:/data/as ~/

Just use single quotes and replace each single quote with '\''.
alias XYZ='rsync -azv -e '\''ssh -o "ProxyCommand ssh -A some#place -W %h:%p"'\'' user#xxx:/data/as ~/'
Or, use a function instead of an alias
XYZ () {
rsync -azv -e 'ssh -o "ProxyCommand ssh -A some#place -W %h:%p"' user#xxx:/data/as ~/ "$#"
}
It's more flexible and gives you a chance to parameterize the command later.

Escape the inner double quote and quote everything with double quote because you cannot escape single quote but only double quote. (sounds a bit funny)
alias foobar="rsync -azv -e 'ssh -o \"ProxyCommand ssh -A some#place -W %h:%p\"' user#xxx:/data/as ~/"
You might want to check this answer.

Related

Read variables in nested quotes

I want to ssh into a host and start a container and run some commands. So the code will be like this:
ssh $host 'screen -L -d -m bash -c "docker run "\
"--network=host -v ~/data:/data myimage:${TAG_NAME}"\
" /bin/bash -c \" some command.... \""'
The question is simple, since I was using single quote, I can't read the ${TAG_NAME}. Is there any way to write this kind of nested quotes and also pass the variable?
You can stop and start your single quotes to include the environment variable, like so:
echo 'foo'"$HOME"'foo'
For your example, the way to include an env var (from your local system) in the command that runs on $host would be:
ssh $host 'screen -L -d -m bash -c "docker run'\
' --network=host -v ~/data:/data myimage:'"$TAG_NAME"\
' /bin/bash -c \" some command.... \""'

Properly Escape $ in a nested remote command

I would like to execute a command on a remote host from another remote host.
HOST1=host1.domain.tld
HOST2=host2.domain.tld
HOST1 is used to connect to HOST2 and the command executes on HOST2. The remote command depends a variable that is calculated on HOST2.
ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C "x=right; echo \$x""
Strangely, the above returns $x while the next command returns wrong instead of an empty line.
ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C "echo \$x""
Question 1: Why is the first command giving me $x?
Question 2: Keeping the double quotes, how do I have it print right?
Section 1: Literal Answers
...to the question precisely as-asked.
Why is the first command giving me $x?
Keep in mind that this command is executed multiple times, and is thus transformed by multiple shells. That transformation looks something like the following (assuming HOST1 of 1.1.1.1 and HOST2 of 2.2.2.2):
ssh -A 1.1.1.1 -C "x=wrong; ssh -A 2.2.2.2. -C "x=right; echo \$x""
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^
...note the arrows? Those are showing where your quoted regions begin and end: Your quote just before x=right is ending your quote that started before x=wrong!
Thus, this tokenizes to two separate commands, written out with one shell word per line below:
# command one: ssh
ssh \
-A \
1.1.1.1 \
-C \
"x=wrong; ssh -A 2.2.2.2. -C "x=right;
# command two: echo
echo \
\$x""
Keeping the double quotes, how do I have it print right?
Backslash-escape the nested quotes so they don't close the quotes you intend to be outer.
ssh -A $HOST1 -C "x=wrong; ssh -A $HOST2 -C \"x=right; echo \$x\""
Section 2: Best-Practice Alternatives
SSH - ProxyCommand
In practice, don't do this kind of explicit nested SSH invocation at all -- just use the ProxyCommand ssh config option:
ssh \
-o "ProxyCommand ssh $HOST1 netcat -w 120 %h %p' \
"$HOST2" 'x=right; echo "$x"'
Bash - nestable eval-safe quote generation
In general, trying to escape things by hand is much more error-prone than telling the shell to do it for you.
host2_cmd='x=right; echo "$x"'
printf -v host1_cmd '%q ' ssh -A "$HOST2" -C "$host2_cmd"
ssh "$HOST1" bash -s <<<"$host1_cmd"
To demonstrate, we could even do this with a third host in the way:
host3_cmd='x=right; echo "$x"'
printf -v host2_cmd '%q ' ssh -A "$HOST3" -C "$host3_cmd"
printf -v host1_cmd '%q ' ssh -A "$HOST2" -C "$host2_cmd"
ssh "$HOST1" bash -s <<<"$host1_cmd"
This works because in ksh and bash, printf %q quotes a string in such a way that it'll evaluate to its current contents when parsed by that same shell.

echo quotes in bash script

I'm creating an automatic network configuration script and in it i have
#!/bin/bash
sudo rm /etc/default/ifplugd
sudo echo "INTERFACES=""
HOTPLUG_INTERFACES="wlan0 eth0"
ARGS="-q -f -u0 -d10 -w -I"
SUSPEND_ACTION="stop"" > /etc/default/ifplugd
however on viewing /etc/default/ifplugd some of the quotes are missing
INTERFACES=
HOTPLUG_INTERFACES=wlan0 eth0
ARGS=-q -f -u0 -d10 -w -I
SUSPEND_ACTION=stop
How do I configure the script so it includes the quotes between the first and last echo ones?
How about:
sudo sh -c 'cat <<END >/etc/default/ifplugd
INTERFACES=""
HOTPLUG_INTERFACES="wlan0 eth0"
ARGS="-q -f -u0 -d10 -w -I"
SUSPEND_ACTION="stop"
END
'
You don't need to explicitly rm, the > redirection will truncate the file before writing the new content.
You need to escape the " marks with a \ prefix, like this:
#!/bin/bash
sudo rm /etc/default/ifplugd
sudo echo "INTERFACES=\"\"
HOTPLUG_INTERFACES=\"wlan0 eth0\"
ARGS=\"-q -f -u0 -d10 -w -I\"
SUSPEND_ACTION=\"stop\"" > /etc/default/ifplugd
A heredoc provides an elegant solution:
sudo tee << EOF /etc/default/ifplugd
INTERFACES=""
HOTPLUG_INTERFACES="wlan0 eth0"
ARGS="-q -f -u0 -d10 -w -I"
SUSPEND_ACTION="stop"
EOF
This way, you don't have to manually quote each and every "" around, and you are not removing the ifplugd file, so you won't need to reset permissions after creating it.

Escaping in wget bash command

wget -q -T 60 --retry-connrefused -t 5 --waitretry=60 --user=ftp2.company.com|company2013 --password=!company2013 -N -P data/parser/company/ ftp://ftp2.company.com/Production/somedata.zip
I'm having trouble with this command, because the password contains an exclamation mark. I tried escaping with \, tried single quotes, and it either gives the output:
wget: missing URL
or
bash: !company2013: event not found
This is really demotivating...
Perhaps this part needs to be quoted to prevent it from being seen as a pipe to another command.
--user='ftp2.company.com|company2013'
And this one too to prevent history expansion with !:
--password='!company2013'
Final:
wget -q -T 60 --retry-connrefused -t 5 --waitretry=60 --user='ftp2.company.com|company2013' --password='!company2013' -N -P data/parser/company/ ftp://ftp2.company.com/Production/somedata.zip
And it's also a good idea to quote the other parts if on later time they have spaces:
wget -q -T 60 --retry-connrefused -t 5 --waitretry=60 --user='ftp2.company.com|company2013' --password='!company2013' -N -P "data/parser/company/" "ftp://ftp2.company.com/Production/somedata.zip"

how do I pass ' [single quote character] as argument in linux [bash shell]?

I've abc.py file which accepts argument -p [password] & -c [command].
Now I can run this file as follows :
./abc.py -p 'a!s!d!f' -c 'ifconfig'
a!s!d!f is my password. As password contains ! character, so I have to send it as argument in ' '. I tried to send it in " " but didn't work.
Now I want to run this code as follows :
./abc.py -p 'a!s!d!f' -c './abc.py -p 'a!s!d!f' -c 'ifconfig''
I'm giving ./abc.py -p 'a!s!d!f' -c 'ifconfig' as a argument to abc.py
The problem is, I'm unable to send ' characher as an argument to abc.py
I need this ' character to be sent as input.
I tried using \ escape character as:
./abc.py -p 'a!s!d!f' -c './abc.py -p \'a!s!d!f\' -c \'ifconfig\''
But not working. How do I do this? Any help would be greatly appreciated.
You need to quote both ' and !:
./abc.py -p 'a!s!d!f' -c "./abc.py -p 'a!s!d!f' -c 'ifconfig'"
$ cat p.py
import sys
print sys.argv
In Korn shell:
$ python p.py -p 'a!s!d!f' -c "./abc.py -p 'a!s!d!f' -c 'ifconfig'"
['p.py', '-p', 'a!s!d!f', '-c', "./abc.py -p 'a!s!d!f' -c 'ifconfig'"]
In bash ! is not treated specially only if enclosed in single quotes, so it can be done like this:
$ python p.py -p 'a!s!d!f' -c './abc.py -p '"'"'a!s!d!f'"'"' -c config'
['p.py', '-p', 'a!s!d!f', '-c', "./abc.py -p 'a!s!d!f' -c config"]
Notice that the result is different then when you quote the whole string with double quotes:
$ python p.py -c "./abcy.py -p 'a\!s\!d\!f' -c 'ifconfig'"
['p.py', '-c', "./abcy.py -p 'a\\!s\\!d\\!f' -c 'ifconfig'"]
In Bash (which follows the POSIX shell standard), single quotes preserve every character literally, which means there is no way to escape contents within single quotes. Your choices are:
Concatenate differently-quoted strings by placing them next to each other:
./abc.py -c "./abc.py -p '"'a!s!d!f'"' -c 'ifconfig'"
Use double-quotes and escape the ! characters:
./abc.py -c "./abcy.py -p 'a\!s\!d\!f' -c 'ifconfig'"

Resources