I need to execute a shell script remotely inside the Linux box from Windows
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Illegal number of parameters"
exit
fi
echo "$1"
Here is the command I ran from Windows command prompt
cmd> plink.exe -ssh username#host -pw gbG32s4D/ -m C:\myscript.sh 5
I am getting output as
"Illegal number of parameters"
Is there any way I can pass command line parameter to shell script which will execute on remote server?
You misunderstand how the -m switch works.
It is just a way to make plink load the commands to send to the server from a local file.
The file is NOT uploaded and executed on the remote server (with arguments).
It's contents is read locally and sent to the server and executed there as if you typed it on a (remote) command line. You cannot give it arguments.
A workaround is to generate the file on the fly locally before running plink from a batch file (say run.bat):
echo echo %1 > script.tmp
plink.exe -ssh username#host -pw gbG32s4D/ -m script.tmp
Then run the batch file with the argument:
run.bat 5
The above will make the script execute echo 5 on the server.
If the script is complex, instead of assembling it locally, have it ready on the server (as #MarcelKuiper suggested) and execute just the script via Plink.
plink.exe -ssh username#host -pw gbG32s4D/ "./myscript.sh %1"
In this case, as we execute just one command, you can pass it on Plink command line, including the arguments. You do not have to use the -m switch with a (temporary) file.
I triggered the Shell script in "commands.txt" from Plink which worked for me like a charm with below method I tried:
You can define your script as an one liner using && in a file (I defined in one liner)
You need to run your command in <
Note: Use first EOF in quote like <<'EOF' but not the last one. Else you will see you code will behave weirdly.
Please see below.
Example:
sudo -i <<'EOF'
<your script here>
EOF
Then, finally run it using Plink:
plink -ssh username#hostname -pw password -m commands.txt
Have you tried putting the command and argument in quotes:
i.e. -m "C:\myscript.sh 5"
I am making a script to securely transfer data between my two machines through scp.
But in the script, it shows an error due to no password. So how can I make my shell script to ask me for password after executing scp command?
Here is my csh script.
# ssh shahk#sj-shahk
# ls -al
echo "Source Location of Remote Server - $1"
echo "Destination Location of Local Server - $2"
echo "File/Folder to be Transferred from Remote Server - $3"
echo "File Transfer Starts"
scp -rv $1/$3 <username>#<hostname>:$2
echo "File Transfer Completed"
# exit
Now I am using the above script with ssh in following way.
ssh <username>#<hostname> "<script name> <args>"
When I use in the above manner, it does not prompt for password while executing scp command.
You can use sshpass
https://www.cyberciti.biz/faq/noninteractive-shell-script-ssh-password-provider/
I have used it once to directly scp or ssh without prompting password.
For example :
sshpass -p 'password' scp file.tar.gz root#xxx.xxx.xxx.194:/backup
As mentioned by the other answer, sshpass will do the job perfectly. In the case where you can not install new packages on your local computer, you can also use expect (installed by default on most distros) to automate your interactive session.
The basic syntax of expect is to wait for the program to display a specific string (expect mystring), which triggers a specific behaviour (send command)
The following script shows the basic structure to implement what you need :
#!/usr/bin/expect -f
# syntax to specify which command to monitor
spawn scp myfile user#remote.host:/dest_folder
# this syntax means we expect the spawned program to display "password: "
# expect can understand regex and glob as well. read the man page for more details
expect "password: "
# the \r is needed to submit the command
send "PASSWORD\r"
# expect "$ " means we wait for anything to be written.
# change if you want to handle incorrect passwords
expect "$ "
send "other_command_to_execute_on_remote\r"
expect "$ "
send "exit\r"
As a side note, you can also set up passwordless authorizations through ssh keys.
#1) create a new ssh key on your local computer
> ssh-keygen -t rsa
#2) copy your public key to your remote server
# you will need to login, but only once. Once the key is on the remote server, you'll be able to connect without password.
> ssh-copy-id -i ~/.ssh/id_rsa.pub user#ip_machine
# OR
> cat ~/.ssh/id_rsa.pub | ssh user#ip_machine "cat - >> ~/.ssh/authorized_keys"
This tutorial explains how to use the keychain tool to manage several ssh keys and users.
ssh <username>#<hostname> "<script name> <args>"
scp will only read a password from a TTY, and it doesn't have a TTY in this case. When you run ssh and specify a command to be executed on the remote system (as you're doing here), ssh by default doesn't allocate a PTY (pseudo-tty) on the remote system. Your script and all of the commands launched from it--including scp--end up running without a TTY.
You can use the ssh -t option to make it allocate a tty on the remote system:
ssh -t <username>#<hostname> "<script name> <args>"
If you get a message like "Pseudo-terminal will not be allocated because stdin is not a terminal", then add another -t:
ssh -tt <username>#<hostname> "<script name> <args>"
This is a follow-on question to the How do you use ssh in a shell script? question. If I want to execute a command on the remote machine that runs in the background on that machine, how do I get the ssh command to return? When I try to just include the ampersand (&) at the end of the command it just hangs. The exact form of the command looks like this:
ssh user#target "cd /some/directory; program-to-execute &"
Any ideas? One thing to note is that logins to the target machine always produce a text banner and I have SSH keys set up so no password is required.
I had this problem in a program I wrote a year ago -- turns out the answer is rather complicated. You'll need to use nohup as well as output redirection, as explained in the wikipedia artcle on nohup, copied here for your convenience.
Nohuping backgrounded jobs is for
example useful when logged in via SSH,
since backgrounded jobs can cause the
shell to hang on logout due to a race
condition [2]. This problem can also
be overcome by redirecting all three
I/O streams:
nohup myprogram > foo.out 2> foo.err < /dev/null &
This has been the cleanest way to do it for me:-
ssh -n -f user#host "sh -c 'cd /whereever; nohup ./whatever > /dev/null 2>&1 &'"
The only thing running after this is the actual command on the remote machine
Redirect fd's
Output needs to be redirected with &>/dev/null which redirects both stderr and stdout to /dev/null and is a synonym of >/dev/null 2>/dev/null or >/dev/null 2>&1.
Parantheses
The best way is to use sh -c '( ( command ) & )' where command is anything.
ssh askapache 'sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'
Nohup Shell
You can also use nohup directly to launch the shell:
ssh askapache 'nohup sh -c "( ( chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'
Nice Launch
Another trick is to use nice to launch the command/shell:
ssh askapache 'nice -n 19 sh -c "( ( nohup chown -R ask:ask /www/askapache.com &>/dev/null ) & )"'
If you don't/can't keep the connection open you could use screen, if you have the rights to install it.
user#localhost $ screen -t remote-command
user#localhost $ ssh user#target # now inside of a screen session
user#remotehost $ cd /some/directory; program-to-execute &
To detach the screen session: ctrl-a d
To list screen sessions:
screen -ls
To reattach a session:
screen -d -r remote-command
Note that screen can also create multiple shells within each session. A similar effect can be achieved with tmux.
user#localhost $ tmux
user#localhost $ ssh user#target # now inside of a tmux session
user#remotehost $ cd /some/directory; program-to-execute &
To detach the tmux session: ctrl-b d
To list screen sessions:
tmux list-sessions
To reattach a session:
tmux attach <session number>
The default tmux control key, 'ctrl-b', is somewhat difficult to use but there are several example tmux configs that ship with tmux that you can try.
I just wanted to show a working example that you can cut and paste:
ssh REMOTE "sh -c \"(nohup sleep 30; touch nohup-exit) > /dev/null &\""
You can do this without nohup:
ssh user#host 'myprogram >out.log 2>err.log &'
Quickest and easiest way is to use the 'at' command:
ssh user#target "at now -f /home/foo.sh"
I think you'll have to combine a couple of these answers to get what you want. If you use nohup in conjunction with the semicolon, and wrap the whole thing in quotes, then you get:
ssh user#target "cd /some/directory; nohup myprogram > foo.out 2> foo.err < /dev/null"
which seems to work for me. With nohup, you don't need to append the & to the command to be run. Also, if you don't need to read any of the output of the command, you can use
ssh user#target "cd /some/directory; nohup myprogram > /dev/null 2>&1"
to redirect all output to /dev/null.
This worked for me may times:
ssh -x remoteServer "cd yourRemoteDir; ./yourRemoteScript.sh </dev/null >/dev/null 2>&1 & "
You can do it like this...
sudo /home/script.sh -opt1 > /tmp/script.out &
It appeared quite convenient for me to have a remote tmux session using the tmux new -d <shell cmd> syntax like this:
ssh someone#elsewhere 'tmux new -d sleep 600'
This will launch new session on elsewhere host and ssh command on local machine will return to shell almost instantly. You can then ssh to the remote host and tmux attach to that session. Note that there's nothing about local tmux running, only remote!
Also, if you want your session to persist after the job is done, simply add a shell launcher after your command, but don't forget to enclose in quotes:
ssh someone#elsewhere 'tmux new -d "~/myscript.sh; bash"'
Actually, whenever I need to run a command on a remote machine that's complicated, I like to put the command in a script on the destination machine, and just run that script using ssh.
For example:
# simple_script.sh (located on remote server)
#!/bin/bash
cat /var/log/messages | grep <some value> | awk -F " " '{print $8}'
And then I just run this command on the source machine:
ssh user#ip "/path/to/simple_script.sh"
If you run remote command without allocating tty, redirect stdout/stderr works, nohup is not necessary.
ssh user#host 'background command &>/dev/null &'
If you use -t to allocate tty to run interactive command along with background command, and background command is the last command, like this:
ssh -t user#host 'bash -c "interactive command; nohup backgroud command &>/dev/null &"'
It's possible that background command doesn't actually start. There's race here:
bash exits after nohup starts. As a session leader, bash exit results in HUP signal sent to nohup process.
nohup ignores HUP signal.
If 1 completes before 2, the nohup process will exit and won't start the background command at all. We need to wait nohup start the background command. A simple workaroung is to just add a sleep:
ssh -t user#host 'bash -c "interactive command; nohup backgroud command &>/dev/null & sleep 1"'
The question was asked and answered years ago, I don't know if openssh behavior changed since then. I was testing on:
OpenSSH_8.6p1, OpenSSL 1.1.1g FIPS 21 Apr 2020
I was trying to do the same thing, but with the added complexity that I was trying to do it from Java. So on one machine running java, I was trying to run a script on another machine, in the background (with nohup).
From the command line, here is what worked: (you may not need the "-i keyFile" if you don't need it to ssh to the host)
ssh -i keyFile user#host bash -c "\"nohup ./script arg1 arg2 > output.txt 2>&1 &\""
Note that to my command line, there is one argument after the "-c", which is all in quotes. But for it to work on the other end, it still needs the quotes, so I had to put escaped quotes within it.
From java, here is what worked:
ProcessBuilder b = new ProcessBuilder("ssh", "-i", "keyFile", "bash", "-c",
"\"nohup ./script arg1 arg2 > output.txt 2>&1 &\"");
Process process = b.start();
// then read from process.getInputStream() and close it.
It took a bit of trial & error to get this working, but it seems to work well now.
YOUR-COMMAND &> YOUR-LOG.log &
This should run the command and assign a process id you can simply tail -f YOUR-LOG.log to see results written to it as they happen. you can log out anytime and the process will carry on
If you are using zsh then use program-to-execute &! is a zsh-specific shortcut to both background and disown the process, such that exiting the shell will leave it running.
A follow-on to #cmcginty's concise working example which also shows how to alternatively wrap the outer command in double quotes. This is how the template would look if invoked from within a PowerShell script (which can only interpolate variables from within double-quotes and ignores any variable expansion when wrapped in single quotes):
ssh user#server "sh -c `"($cmd) &>/dev/null </dev/null &`""
Inner double-quotes are escaped with back-tick instead of backslash. This allows $cmd to be composed by the PowerShell script, e.g. for deployment scripts and automation and the like. $cmd can even contain a multi-line heredoc if composed with unix LF.
First follow this procedure:
Log in on A as user a and generate a pair of authentication keys. Do not enter a passphrase:
a#A:~> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/a/.ssh/id_rsa):
Created directory '/home/a/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/a/.ssh/id_rsa.
Your public key has been saved in /home/a/.ssh/id_rsa.pub.
The key fingerprint is:
3e:4f:05:79:3a:9f:96:7c:3b:ad:e9:58:37:bc:37:e4 a#A
Now use ssh to create a directory ~/.ssh as user b on B. (The directory may already exist, which is fine):
a#A:~> ssh b#B mkdir -p .ssh
b#B's password:
Finally append a's new public key to b#B:.ssh/authorized_keys and enter b's password one last time:
a#A:~> cat .ssh/id_rsa.pub | ssh b#B 'cat >> .ssh/authorized_keys'
b#B's password:
From now on you can log into B as b from A as a without password:
a#A:~> ssh b#B
then this will work without entering a password
ssh b#B "cd /some/directory; program-to-execute &"
I think this is what you need:
At first you need to install sshpass on your machine.
then you can write your own script:
while read pass port user ip; do
sshpass -p$pass ssh -p $port $user#$ip <<ENDSSH1
COMMAND 1
.
.
.
COMMAND n
ENDSSH1
done <<____HERE
PASS PORT USER IP
. . . .
. . . .
. . . .
PASS PORT USER IP
____HERE
How can I send a command (not to open a file) with PuTTY that will run on a Linux terminal?
For example:
putty.exe 10.31.2.121 -l root -pw password | echo "Hi"
So that I will see the "Hi" on the Linux console?
Use plink.exe (from the developer of PuTTY).
And do something like the following
C:\putty\plink.exe user1#192.168.0.1 -pw P#55W0rD!
-m command.txt
I took this from Automate Cisco SSH connections with plink on Windows.
I have a program that can be run via remote plink ssh on a different PC using windows command prompt
plink [username]#[ip address] -pw [password] ./program
or:
plink -ssh -l [username] -pw [password] [ip address] ./program
but somehow the program will end prematurely. Program runs, but terminates before the program had run its course. It doesn't happen to all my programs though.
To clearify, I can run my program with following command line
plink [username]#[ip address] -pw [password]
which log me in to remote system, from there I can run ./program to its entirety.
but if I try plink [username]#[ip address] -pw [password] ./program in one line, it will quit in the middle.
I wonder if anyone encounter the same problem before? How do you solve it? Thanks
plink [username]#[ip address] -pw [password] -m program.txt
Execute remote commands from local file. You can create a local command file with Unix commands in it, and run it remotely and automatically. Example -- "find /usr/local -name pmapp -print" in cmds.txt can be run with:
so use -m option that help you to execute remote commands
cheers.