How to pass local variable to remote ssh commands? - linux

I need to execute multiple commands on remote machine, and use ssh to do so,
ssh root#remote_server 'cd /root/dir; ./run.sh'
In the script, I want to pass a local variable $argument when executing run.sh, like
ssh root#remote_server 'cd /root/dir; ./run.sh $argument'
It does not work, since in single quote $argument is not interpreted the expected way.
Edit: I know double quote may be used, but is there any side effects on that?

You can safely use double quotes here.
ssh root#remote_server "cd /root/dir; ./run.sh $argument"
This will expand the $argument variable. There is nothing else present that poses any risk.
If you have a case where you do need to expand some variables, but not others, you can escape them with backslashes.
$ argument='-V'
$ echo "the variable \$argument is $argument"
would display
the variable $argument is -V
You can always test with double quotes to discover any hidden problems that might catch you by surprise. You can always safely test with echo.
Additionally, another way to run multiple commands is to redirect stdin to ssh. This is especially useful in scripts, or when you have more than 2 or 3 commands (esp. any control statements or loops)
$ ssh user#remoteserver << EOF
> # commands go here
> pwd
> # as many as you want
> # finish with EOF
> EOF
output, if any, of commands will display
$ # returned to your current shell prompt
If you do this on the command line, you'll get a stdin prompt to write your commands. On the command line, the SSH connection won't even be attempted until you indicate completion with EOF. So you won't see results as you go, but you can Ctrl-C to get out and start over. Whether on the command line or in a script, you wrap up the sequence of commands with EOF. You'll be returned to your normal shell at that point.

You could run xargs on the remote side:
$ echo "$argument" | ssh root#remote_server 'cd /root/dir; xargs -0 ./run.sh'
This avoids any quoting issues entirely--unless your argument has null characters in it, I suppose.

Related

how to execute ssh comand on .sh file?

I trying to create a .sh file that execute things like "pwd" or "ls" command.
My problem its when i execute the .sh file.
Its seems not recognize the tasks
I tried to use echo
Example : echo 'lsApps' or echo "lsApps"
but it prints the name of the task instead execute the comand
for example i want to execute a .ssh file that makes a pwd
VAR_1=pwd
echo $VAR_1
but it prints me pwd instead the current path ...
Any idea?
echo is used to print on the screen (man page reference). If you do echo 'IsApps' it will take it as a string and print it. If you want to execute a command you can just do it by doing IsApps (acutes not quotes, acute is usually below the escape key). This will execute the command and show the output on the screen. If you want to store the output of the command in a variable, you can do
<variable_name>=`IsApps`
This will store the output in the variable. Note that there is no space between variable name and the command. Also, those are not quotes but instead acutes. To print the variable on screen you can use echo by doing echo $<variable_name>
If you don't want to see the output at all. You can do
IsApps > /dev/null
this will execute the command but you will not see any stdout on your screen.
As far as ssh is concerned, do ssh-keygen and then ssh-copy-id user#remote_ip to set ssh keys so that you don't have to enter your password with ssh. Once you have done that, you can use ssh user#remote_ip in your shell script.

ssh to remote machine via proxy server to run a script with parameters

I want to ssh to a machine via proxy server and run a script on that server with the inputs as parameters passed
I am using below :
ssh -t tooladm#200.81.36.188 "ssh -t tooladm#apuatt01" ". ./.profile >/dev/null 2>&1; cd /astxpinfs/ast/tooladm/JHF_SYNC_Particular_HF ; ./SyncToSite.ksh $product $release "${hf_list}" ${LOG_DIR_NAME} 2>&1 > /dev/null"
For clearance :
Suppose I am in machine A, and want to run the script located in machine apuatt01
There is no direct connectivity b/w machine A and apuatt01
So I am connecting apuatt01 via 200.81.36.188
By using this, I am not able to run the above script
Please can you help, where I am doing wrong
You can use Bash here document to make the script cleaner:
ssh -t tooladm#200.81.36.188 -- ssh -t tooladm#apuatt01 <<EOS
source .profile >/dev/null 2>&1
cd /astxpinfs/ast/tooladm/JHF_SYNC_Particular_HF
./SyncToSite.ksh $product $release "${hf_list}" ${LOG_DIR_NAME} 2>&1 > /dev/null
EOS
Note, the double dash separates the command from arguments passed to ssh.
This syntax works in ksh, too. From the KornShell manual(man ksh):
<<[-]word The shell input is read up to a line that is the same
as word after any quoting has been removed, or to an end-of-file.
No parameter substitution, command substitution, arithmetic
substitution or file name generation is performed on word. The
resulting document, called a here-document, becomes the standard
input. If any character of word is quoted, then no interpretation is
placed upon the characters of the document; otherwise, parameter
expansion, command substitution, and arithmetic substitution occur,
\new- line is ignored, and \ must be used to quote the characters \,
$, `. If - is appended to <<, then all leading tabs are stripped from
word and from the document. If # is appended to <<, then leading
spaces and tabs will be stripped off the first line of the document
and up to an equivalent indentation will be stripped from the
remaining lines and from word. A tab stop is assumed to occur at
every 8 columns for the purposes of determining the indentation.

Having trouble with running a command over ssh

This command isn't working as expected:
ssh root#<machineIP> -- sh -c "echo \$\(cat /tmp/testfile\) > /testfile"
My intent is to copy the contents of /tmp/testfile to /testfile. Real simple. But I find that /testfile has nothing in it. The file is created (in the case it doesn't exist).
echo command works fine (minus the escapes) if run from command line on the remote server. But doesn't work when running it through ssh. Originally I actually had a more complex command with 'sed', but simplified what wasn't working down to this.
Both remote and local servers are CentOS7.
I found I had to escape the $ and (). Is this causing me problems? Is not the correct way to run this command?
ssh will take all the command parameters, join them on spaces and then run that in the remote shell.
That means that the command being executed is basically what you'd get if you replaced ssh with echo:
$ echo sh -c "echo \$(cat /tmp/testfile) > /testfile"
sh -c echo $(cat /tmp/testfile) > /testfile
The quoting is lost, so the resulting command is equivalent to sh -c echo > /testfile which makes it empty.
Instead, just take the command you want to run and wrap it in single quotes:
ssh root#host 'echo $(cat /tmp/testfile) > /testfile'
Make sure never to use echo or $() when copying files though. I'm assuming this is a stand-in for something better.

How to echo line with multiple quotes/special characters into file?

I am trying to echo the following line into a .profile but it keeps getting confused by either the many quotes or special characters.
bind '"e[A": history-search-backward'
I've tried all sorts of things but can't get it nailed.
This is what I currently have:
sudo su -c 'echo "bind \'\"\\e[A\": history-search-backward\'" >> /etc/profile' -
This is what it returns:
su: user '"\e[A": does not exist
Yet if I just use:
echo bind \'\"\\e[A\": history-search-backward\'" >> /home/user/testfile
It works just fine.
I have all manner of "sudo su -c "echo blah..." in the rest of my script that work just fine.
Any ideas?
Try this
sudo su -c $'echo \"bind \'\"\\e[A\": history-search-backward\'\" >> /etc/profile\' -'
From the bash man page:
A single quote may not occur between single quotes, even when preceded by a backslash.
Text quoted by $'...' may contain backslash-escaped quotes, both single and double.
Another option is to add a simpler expression to ~/.inputrc:
echo '"\e[A": history-search-backward' >> ~/.inputrc
There doesn't seem to be a system-wide equivalent of .inputrc that is read by all users. Also, this makes the key binding available to any program that uses readline. If you really do want to restrict it to bash, add a conditional expression:
cat >> ~/.inputrc <<'EOF'
$if Bash
"\e[A": history-search-backward
$endif
EOF
Every character is interpreted literally between single quotes, except ' itself. So you can put a single quote inside a literal string like this: 'single'\''quoted' is the string single'quoted.
Your command is complicated because there are two shells involved: the shell you're running this command from, and the shell that su runs. Note that it's weird to run sudo su since sudo already runs the specified command as root; sudo sh -c … makes more sense. So you need to quote for both. It's usually clearest to use single quotes for the outer shell, and double quotes or single quotes or backslashes for the inner shell.
There's another problem with your command: you're targeting the wrong file. /etc/profile is only read by login shells, whereas the bind command is specific to bash but should be read by all instances of bash, not just login shells. Instead of writing this line to /etc/profile, you should write it to the system-wide bashrc, if there is one (it's usually /etc/bash.bashrc).
sudo sh -c 'echo "bind '\''\"\\e[A\": history-search-backward'\''" >>/etc/bash.bashrc'
You may put this setting directly into the readline configuration file, /etc/inputrc. You'll save on a level of quoting.
sudo sh -c 'echo '\''"\e[A": history-search-backward'\'' >>/etc/inputrc'
An easier way to pass an arbitrary string to a command would be to pass it as input instead of as an argument and use a here document.
sudo sh -c 'cat >>/etc/inputrc' <<'EOF'
"\e[A": history-search-backward
EOF

Execute a list of Unix commands using ssh

I want to run the same set of Unix commands on multiple machines. I am aware of ssh and something like the below. I want to write a shell script to do this. I have access to bash and ksh and I'm on Linux Red Hat 5.
ssh root#ip "echo \$HOME"
However, I have 2 questions:
I keep getting prompted for a password. How can I have it not prompt me and enter the password automatically?
How can I execute multiple commands?
You should use key based authentification, possibly coupled with ssh-agent to remember key passphrase.
You can invoke sh -c as the command, and pass it a string containing the list of command to execute. ssh invoke a shell on the remote machine, so you can pass a list of command as a string.
For example:
$ ssh user#ip "echo 'Hello world'; whoami; cd / ; ls"
Use ssh-agent to set up authentication for all commands. Or put your multiple commands into a single shell script.
Send a list of commands to the remote shell. Possible solutions:
use ", escape line breaks to format code and end each substatement with ;.
Disadvantage: " should not be used inside the command list.
ssh user#ip "\
echo 'Hallo sir, how are you doing?';\
whoami;\
cd /;\
ls\
"
use ' and format code with regular line breaks.
Disadvantage: ' should not be used inside the command list.
ssh user#ip '
echo "Hallo sir, how are you doing?"
whoami
cd /
ls
'
Note: using " or ' inside the respective statements will not necessarily result in an error. Though you may get unsuspected results.

Resources