Problems with fish shell and ssh remote commands - linux

I use fish shell on my desktop.
We use many servers running nginx within docker. I've tried to create a function so I can ssh to the servers and then log into the docker.
The problem is fish is complaining about the $ in the command, but the command is the one to be executed on the remote server (running bash), not on my machine running fish. I've simplified the script to make it easier to see.
config.fish snippet
function ssh-docker-nginx
ssh -t sysadmin#10.10.10.10 "sudo bash && docker exec -it $(docker ps | grep -i nginx | awk '{print $1}') bash"
end
Fish error:
$(...) is not supported. In fish, please use '(docker)'.
~/.config/fish/config.fish (line 59): ssh -t sysadmin#10.10.10.10 "sudo bash && docker exec -it $(docker ps | grep -i nginx | awk '{print $1}') bash"
^
from sourcing file ~/.config/fish/config.fish
called during startup
Is there a way to get fish to ignore this?

You'll want to single-quote that argument.
In double-quotes (") fish will try to expand everything that starts with a $, so it will see that $( and then print the error for it. But it will also see the $1 in your arguments to awk and expand that.
And when you want single-quotes to go to the called command (like here, where you want the argument to awk to be single-quoted because this'll go through bash's expansion), you need to escape the quotes with \.
Try
ssh -t sysadmin#10.10.10.10 'sudo bash && docker exec -it $(docker ps | grep -i nginx | awk \'{print $1}\') bash'

Thanks for the great advice and tip above about the single/double quotes. Unfortunately the escaped quotes in awk did not play nicely being passed to ssh.
After various options, I settled with this approach (which needed force tty):
function ssh-docker-nginx
cat docker-bash.sh | ssh -t -t sysadmin#10.10.10.10
end
# docker-bash.sh
#!/bin/bash
sudo chmod 777 /var/run/docker.sock
sudo docker exec -it $(docker ps | grep -i nginx | awk '{print $1}') bash

Related

Execute a remote command over SSH with remote evaluation

I'm trying to run a command over SSH and want the evaluation of an expression in the command to happen on the remote machine.
I'm trying to run this:
ssh -A username#ip "sudo docker exec -it "$(docker ps | grep 'some' | awk '{ print $1 }')" python manage.py shell"
but the expression $(docker ps | grep 'some' | awk '{ print $1 }') is not evaluated correctly on the remote machine when I use the ssh command.
To confirm, if I first ssh into the remote machine, and then run sudo docker exec -it "$(docker ps | grep 'some' | awk '{ print $1 }')" python manage.py shell, it does evaluate correctly and gives me a shell successfully. I just cannot make it work directly from my local machine as a part of an argument to the ssh command.
What can I do to make it work as a part of the ssh command?
The problem with doing the command below is that I receive a Pseudo-terminal will not be allocated because stdin is not a terminal. message from my terminal (iTerm) and do not get a shell like I'm expecting after the execution of this command.
ssh -A username#ip <<'EOL'
name="$(docker ps | grep 'some' | awk '{ print $1 }')"
docker exec -it $name python manage.py shell
EOL
You need to escape all the characters that need to be interpreted by the remote shell like so:
ssh -A username#ip "sudo docker exec -it \"\$(docker ps | grep 'some' | awk '{ print \$1 }')\" python manage.py shell"
This way you will send the quotes belonging to the -it argument, as well as the $ sign unchanged and the remote shell will execute them.

Using Variable in Shell script as input for another command

#!/bin/bash
sudo docker-compose -f /home/administrator/compose/docker-compose.yml up --build -d
OUTPUT=$(docker ps | grep 'nginx_custom' | awk '{ print $1 }')
echo $OUTPUT
sudo docker $OUTPUT nginx -s reload
This the the ID that get´s printed correctly in the console.
6e3b3aa3fbc4
This command works fine.
docker exec 6e3b3aa3fbc4 nginx -s reload
However the variable seems not to get passed to the command here:
sudo docker $OUTPUT nginx -s reload
I am quite unfamiliar with the shell :(. How do I pass the variable to a command that is longer than just echo?
add set -x to the script and see what happens:
you can probably get rid of grep and incorporate it inside awk
#!/bin/bash
set -x
sudo docker-compose -f /home/administrator/compose/docker-compose.yml up --build -d
OUTPUT=$(docker ps | awk '/ngnix_custom/{ print $1 }')
echo $OUTPUT
sudo docker $OUTPUT nginx -s reload

How to handle quotes, backtick special characters for running linux bash shell command in remote server

Someone, please help me in correcting below command I wasted more than a day fixing below but failed, please help, I will be using below in ansible shell module.
ssh -o ConnectTimeout=5 splunk#10.145.32.172 '
sdline="`
grep -n TA-aws-hf-{{client_code}}-{{env_name}} /opt/splunk/etc/system/local/serverclass.conf
| awk -F \":\" \'{print $1}\'
`
&& sed -ie \"$sdline,`
echo $sdline + 3
| bc
`d\" /opt/splunk/etc/system/local/serverclass.conf
"
> ^C
Even tried below way:
ssh -o ConnectTimeout=5 splunk#10.145.32.172 exec sdline=`grep -n TA-aws-hf-{{client_code}}-{{env_name}} /opt/splunk/etc/system/local/serverclass.conf|awk -F ":" '{print $1}'` && sed -ie "$sdline,`echo $sdline + 3|bc` d" /opt/splunk/etc/system/local/serverclass.conf
grep: /opt/splunk/etc/system/local/serverclass.conf: No such file or directory
bash: line 0: exec: sdline=: not found
Context: It seems this question originated as an XY Problem. OP appears to want to remove the 3 lines including and after the string "TA-aws-hf-{{client_code}}-{{env_name}}".
Backticks are deprecated; use $(modern $(command) substitution) when necessary. It is not necessary in this case.
If your remote server has GNU sed:
ssh splunk#10.145.32.172 'sed -i "/TA-aws-hf-{{client_code}}-{{env_name}}/,+2d" /opt/splunk/etc/system/local/serverclass.conf'
If that gives you sed: -e expression #1, char 19: unexpected ',':
ssh splunk#10.145.32.172 '
cd /opt/splunk/etc/system/local
awk "/TA-aws-hf-{{client_code}}-{{/ {i=-3} i++>0" \
serverclass.conf > temp && mv $_ serverclass.conf
'
Your remote command is quite complicated.
I suggest the following:
Use ssh to gain interactive shell in 10.145.32.172
Create a script on 10.145.32.172 that do the work, with everything hard coded.
Refactor command line parameters to your script.
Call your script remotely from your local machine.
This strategy simplify the script and its maintenance. Allowing you to send only the important parameters.
If you have to deploy the script on many remote machines. Use shared storage resources, like NFS. Optionally copy the script using scp prior to running it.

Bash for loops on a remote server

I am attempting to run multiple commands via a bash script on a remote server. specifically, the for loop to be run on the remote server is giving me issues. I suspect it is because I don't know how to properly escape characters or use $().
Below is the code.
ssh (user)#(server) <<EOF
sudo su - (username)
whoami
'for e in $(`ls -lrt /usr/jboss/jbosseap | awk '{print $9}' | grep multichannel`);
do
echo "$e";
done'
Removing user and server names for obvious reasons. Just concentrate on the for loop. when I run that for loop command line (without the $()) its works fine. Just not sure how to nest it in a remote call.
Thanks very much for any and all help!
If you've got a complex script that you're trying to run over ssh you're going to be better off putting that script in a file and piping that file into ssh like:
cat remote_script.sh | ssh user#host
or:
cat remote_script.sh | ssh user#host sudo -u username
And now you don't have to worry about N levels of escaping.
You can run it as below .
here file "list " includes your list of nodes and script should be present in all nodes
for i in $(cat list ) ;do ssh -o StrictHostKeyChecking=no $i "/path/your_script" ;done

BASH automatically adding quotes to string

I'm trying to write a simple bash script that executes a command with one string variable. Upon execution bash adds single quotes to the string variable making the command useless. How do I execute the command without the quotes from the bash script?
#!/bin/bash
key=$(echo $1 | tr '[:lower:]' '[:upper:]')
sudo tee /proc/acpi/bbswitch \<\<\<$key
the output I get is
~/scripts$ bash -x nvidia on
++ echo on
++ tr '[:lower:]' '[:upper:]'
+ key=ON
+ sudo tee /proc/acpi/bbswitch '<<<ON'
the two commands I want to run without the quotes are either
sudo tee /proc/acpi/bbswitch <<<ON
or
sudo tee /proc/acpi/bbswitch <<<OFF
The problem isn't the quotes, it's that sudo doesn't execute the command via the shell. So metacharacters like <<< don't have any special meaning when they're given as sudo arguments. You need to invoke the shell explicitly:
sudo bash -c "tee /proc/acpi/bbswitch <<<$key"
But there doesn't really seem to be a need to use a here-string for this. Just use:
echo "$key" | sudo tee /proc/acpi/bbswitch
There's no need to quote the <<< operator. sudo doesn't read from its standard input by default; it passes it through to the command it runs.
sudo tee /proc/acpi/bbswitch <<< $key

Resources