Bash Script to start a process on a remote Linux Machine and keep it detached from the starting server - linux

I'm new to Linux (Red Hat) and I'm trying to automate the Eggplant tests I've come up with for our GUI based software. This will be run nightly.
I'll be running the base script on server 001. It will copy over the latest version of our software to a remote PC which is serving as test bench then it's to kick off a Bash script on the test bench which configures the environment then starts up the software.
I've tried:
ssh test#111.111.111.002 'bash -s' < testConfig.sh
ssh test#111.111.111.002 'bash -s testConfig.sh < /dev/nul > testConfig.log 2>&1 &'
ssh -X test#111.111.111.002 'testConfig.sh'
First one just fails, the second tries to start the software but instead of running on the test bench it tries running on the server. Of course with the third one it opens up windows on the server and runs the software; but I need the display on the test bench not the server.

A coworker happened by and saw my difficulty and suggested this, and it worked:
ssh user#1.1.1.1 'setenv DISPLAY :0.0 && testConfig.sh'

Try below and let us know. Using double quotes instead of single quotes.
ssh user#1.1.1.1 "bash -s" < ./testConfig.sh
make sure testConfig.sh is in the directory from where you are ssh'ing else use absolute path name for e.g. /home/qwe/testConfig.sh
Please also mention the error you are getting if any.

Related

Perform bash command after connecting to Ubuntu server (Windows 10)

I'm trying to make a simple Windows batch script that will make my life easier, but i don't know if it's quite possible. It basically automatically connect to the Ubuntu server using SSH. But when i enter the server, none of my commands work (as you would expect, since is a different terminal). However, i made a shell script and placed in the root directory of the server (ubuntu#ip-182-74-3-112:~$) that performs the actions, i just need to execute this script automatically when i connect to the Ubuntu server. Is it possible?
Batch script:
cd "C:\Users\myUser\Documents"
ssh -i .\my_server.pem ubuntu#www.website.com.br
// ./restart.sh (doesn't work)
Shell script:
#!/bin/bash
cd "server/glassfish4/glassfish/bin/"
for i in 1 2 3; do
sudo ./asadmin stop-domain domain1
done
for i in 1 2; do
sudo ./asadmin start-domain domain1
done
The answer was so simple that didn't come to my mind. I just changed
cd "C:\Users\myUser\Documents"
ssh -i .\my_server.pem ubuntu#www.website.com.br
to
cd "C:\Users\myUser\Documents"
ssh -i .\my_server.pem ubuntu#www.website.com.br "./restart.sh; bash"
Ignore my question, i'm just leaving here for convenience

Running bash script over SSH [duplicate]

I have to run a local shell script (windows/Linux) on a remote machine.
I have SSH configured on both machine A and B. My script is on machine A which will run some of my code on a remote machine, machine B.
The local and remote computers can be either Windows or Unix based system.
Is there a way to run do this using plink/ssh?
If Machine A is a Windows box, you can use Plink (part of PuTTY) with the -m parameter, and it will execute the local script on the remote server.
plink root#MachineB -m local_script.sh
If Machine A is a Unix-based system, you can use:
ssh root#MachineB 'bash -s' < local_script.sh
You shouldn't have to copy the script to the remote server to run it.
This is an old question, and Jason's answer works fine, but I would like to add this:
ssh user#host <<'ENDSSH'
#commands to run on remote host
ENDSSH
This can also be used with su and commands which require user input. (note the ' escaped heredoc)
Since this answer keeps getting bits of traffic, I would add even more info to this wonderful use of heredoc:
You can nest commands with this syntax, and that's the only way nesting seems to work (in a sane way)
ssh user#host <<'ENDSSH'
#commands to run on remote host
ssh user#host2 <<'END2'
# Another bunch of commands on another host
wall <<'ENDWALL'
Error: Out of cheese
ENDWALL
ftp ftp.example.com <<'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH
You can actually have a conversation with some services like telnet, ftp, etc. But remember that heredoc just sends the stdin as text, it doesn't wait for response between lines
I just found out that you can indent the insides with tabs if you use <<-END!
ssh user#host <<-'ENDSSH'
#commands to run on remote host
ssh user#host2 <<-'END2'
# Another bunch of commands on another host
wall <<-'ENDWALL'
Error: Out of cheese
ENDWALL
ftp ftp.example.com <<-'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH
(I think this should work)
Also see
http://tldp.org/LDP/abs/html/here-docs.html
Also, don't forget to escape variables if you want to pick them up from the destination host.
This has caught me out in the past.
For example:
user#host> ssh user2#host2 "echo \$HOME"
prints out /home/user2
while
user#host> ssh user2#host2 "echo $HOME"
prints out /home/user
Another example:
user#host> ssh user2#host2 "echo hello world | awk '{print \$1}'"
prints out "hello" correctly.
This is an extension to YarekT's answer to combine inline remote commands with passing ENV variables from the local machine to the remote host so you can parameterize your scripts on the remote side:
ssh user#host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'
# commands to run on remote host
echo $ARG1 $ARG2
ENDSSH
I found this exceptionally helpful by keeping it all in one script so it's very readable and maintainable.
Why this works. ssh supports the following syntax:
ssh user#host remote_command
In bash we can specify environment variables to define prior to running a command on a single line like so:
ENV_VAR_1='value1' ENV_VAR_2='value2' bash -c 'echo $ENV_VAR_1 $ENV_VAR_2'
That makes it easy to define variables prior to running a command. In this case echo is our command we're running. Everything before echo defines environment variables.
So we combine those two features and YarekT's answer to get:
ssh user#host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'...
In this case we are setting ARG1 and ARG2 to local values. Sending everything after user#host as the remote_command. When the remote machine executes the command ARG1 and ARG2 are set the local values, thanks to local command line evaluation, which defines environment variables on the remote server, then executes the bash -s command using those variables. Voila.
<hostA_shell_prompt>$ ssh user#hostB "ls -la"
That will prompt you for password, unless you have copied your hostA user's public key to the authorized_keys file on the home of user .ssh's directory. That will allow for passwordless authentication (if accepted as an auth method on the ssh server's configuration)
I've started using Fabric for more sophisticated operations. Fabric requires Python and a couple of other dependencies, but only on the client machine. The server need only be a ssh server. I find this tool to be much more powerful than shell scripts handed off to SSH, and well worth the trouble of getting set up (particularly if you enjoy programming in Python). Fabric handles running scripts on multiple hosts (or hosts of certain roles), helps facilitate idempotent operations (such as adding a line to a config script, but not if it's already there), and allows construction of more complex logic (such as the Python language can provide).
cat ./script.sh | ssh <user>#<host>
chmod +x script.sh
ssh -i key-file root#111.222.3.444 < ./script.sh
Try running ssh user#remote sh ./script.unx.
Assuming you mean you want to do this automatically from a "local" machine, without manually logging into the "remote" machine, you should look into a TCL extension known as Expect, it is designed precisely for this sort of situation. I've also provided a link to a script for logging-in/interacting via SSH.
https://www.nist.gov/services-resources/software/expect
http://bash.cyberciti.biz/security/expect-ssh-login-script/
ssh user#hostname ". ~/.bashrc;/cd path-to-file/;. filename.sh"
highly recommended to source the environment file(.bashrc/.bashprofile/.profile). before running something in remote host because target and source hosts environment variables may be deffer.
I use this one to run a shell script on a remote machine (tested on /bin/bash):
ssh deploy#host . /home/deploy/path/to/script.sh
if you wanna execute command like this
temp=`ls -a`
echo $temp
command in `` will cause errors.
below command will solve this problem
ssh user#host '''
temp=`ls -a`
echo $temp
'''
If the script is short and is meant to be embedded inside your script and you are running under bash shell and also bash shell is available on the remote side, you may use declare to transfer local context to remote. Define variables and functions containing the state that will be transferred to the remote. Define a function that will be executed on the remote side. Then inside a here document read by bash -s you can use declare -p to transfer the variable values and use declare -f to transfer function definitions to the remote.
Because declare takes care of the quoting and will be parsed by the remote bash, the variables are properly quoted and functions are properly transferred. You may just write the script locally, usually I do one long function with the work I need to do on the remote side. The context has to be hand-picked, but the following method is "good enough" for any short scripts and is safe - should properly handle all corner cases.
somevar="spaces or other special characters"
somevar2="!##$%^"
another_func() {
mkdir -p "$1"
}
work() {
another_func "$somevar"
touch "$somevar"/"$somevar2"
}
ssh user#server 'bash -s' <<EOT
$(declare -p somevar somevar2) # transfer variables values
$(declare -f work another_func) # transfer function definitions
work # call the function
EOT
The answer here (https://stackoverflow.com/a/2732991/4752883) works great if
you're trying to run a script on a remote linux machine using plink or ssh.
It will work if the script has multiple lines on linux.
**However, if you are trying to run a batch script located on a local
linux/windows machine and your remote machine is Windows, and it consists
of multiple lines using **
plink root#MachineB -m local_script.bat
wont work.
Only the first line of the script will be executed. This is probably a
limitation of plink.
Solution 1:
To run a multiline batch script (especially if it's relatively simple,
consisting of a few lines):
If your original batch script is as follows
cd C:\Users\ipython_user\Desktop
python filename.py
you can combine the lines together using the "&&" separator as follows in your
local_script.bat file:
https://stackoverflow.com/a/8055390/4752883:
cd C:\Users\ipython_user\Desktop && python filename.py
After this change, you can then run the script as pointed out here by
#JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883 with:
`plink root#MachineB -m local_script.bat`
Solution 2:
If your batch script is relatively complicated, it may be better to use a batch
script which encapsulates the plink command as well as follows as pointed out
here by #Martin https://stackoverflow.com/a/32196999/4752883:
rem Open tunnel in the background
start plink.exe -ssh [username]#[hostname] -L 3307:127.0.0.1:3306 -i "[SSH
key]" -N
rem Wait a second to let Plink establish the tunnel
timeout /t 1
rem Run the task using the tunnel
"C:\Program Files\R\R-3.2.1\bin\x64\R.exe" CMD BATCH qidash.R
rem Kill the tunnel
taskkill /im plink.exe
This bash script does ssh into a target remote machine, and run some command in the remote machine, do not forget to install expect before running it (on mac brew install expect )
#!/usr/bin/expect
set username "enterusenamehere"
set password "enterpasswordhere"
set hosts "enteripaddressofhosthere"
spawn ssh $username#$hosts
expect "$username#$hosts's password:"
send -- "$password\n"
expect "$"
send -- "somecommand on target remote machine here\n"
sleep 5
expect "$"
send -- "exit\n"
You can use runoverssh:
sudo apt install runoverssh
runoverssh -s localscript.sh user host1 host2 host3...
-s runs a local script remotely
Useful flags:
-g use a global password for all hosts (single password prompt)
-n use SSH instead of sshpass, useful for public-key authentication
If it's one script it's fine with the above solution.
I would set up Ansible to do the Job. It works in the same way (Ansible uses ssh to execute the scripts on the remote machine for both Unix or Windows).
It will be more structured and maintainable.
It is unclear if the local script uses locally set variables, functions, or aliases.
If it does this should work:
myscript.sh:
#!/bin/bash
myalias $myvar
myfunction $myvar
It uses $myvar, myfunction, and myalias. Let us assume they is set locally and not on the remote machine.
Make a bash function that contains the script:
eval "myfun() { `cat myscript.sh`; }"
Set variable, function, and alias:
myvar=works
alias myalias='echo This alias'
myfunction() { echo This function "$#"; }
And "export" myfun, myfunction, myvar, and myalias to server using env_parallel from GNU Parallel:
env_parallel -S server -N0 --nonall myfun ::: dummy
Extending answer from #cglotr. In order to write inline command use printf, it useful for simple command and it support multiline using char escaping '\n'
example :
printf "cd /to/path/your/remote/machine/log \n tail -n 100 Server.log" | ssh <user>#<host> 'bash -s'
See don't forget to add bash -s
There is another approach ,you can copy your script in your host with scp command then execute it easily .
First, copy the script over to Machine B using scp
[user#machineA]$ scp /path/to/script user#machineB:/home/user/path
Then, just run the script
[user#machineA]$ ssh user#machineB "/home/user/path/script"
This will work if you have given executable permission to the script.

Execute bash script on a remote-linux

I have a bash script lets say test.sh. This script contains the following:
#!/bin/bash
echo "khaled"
ads2 svcd&
This script simply prints my name (just for test purposes) and execute ads-service application in the background. When i run the script on my ubuntu, it works correctly. As a test i checked which programs run on the kernel
As you see. ads2 runs and has 12319 process-id.
Now what I'm trying to do is to run the script on the ubuntu, however remotely from a windows pc.
Therefore i opened command-line on windows and executed the following command:
ssh nvidia#ubuntu ip-address ~/test.sh
And i get the following
As you see the scripts run and prints khaled,however on windows command line and what i want is that the script is executed on the ubuntu. this justify why the lineads2 svcd& doe not do anything, neither on windows (which makes sense, since ads2 is installed on ubuntu) nor on linux.
So how can i execute the script on ubuntu ?
thanks in advance
Use the full path to start ads2. When using remote SSH your environment variables may be different than in a local shell.
#!/bin/bash
echo "khaled"
/home/nvidia/ads2 svcd&
Not sure where ads2 is located.
Try the following to locate it on your Ubuntu local shell.
command -v ads2
You may also need nohup to persist the process beyond the life of the SSH session.
If you have the script on the remote server and you want to run this, you would add back ticks,
ssh user#server './test/file.sh'
The script's output would be sent to your local machine, as if you ran the command from your local machine.

Suppress 'Warning: no access to tty' in ssh

I have a short simple script, that compiles a .c file and runs it on a remote server running tcsh and then just gives back control to my machine (this is for school, I need my programs to work properly on the lab computers but want to edit them etc. on my machine). It runs commands this way:
ssh -T user#server << EOF
cd cs4400/$dest
gcc -o $efile $file
./$efile
EOF
So far it works fine, but it gives this warning every time I do this:
Warning: no access to tty (Bad file descriptor).
Thus no job control in this shell.
I know this technically isn't a problem, but it's SUPER annoying. I'm trying to do school work, checking the output of my program etc., and this clutters everything, and I HATE it.
I'm running this version of ssh on my machine:
OpenSSH_6.1p1 Debian-4, OpenSSL 1.0.1c 10 May 2012
This version of tcsh on the server:
tcsh 6.17.00 (Astron) 2009-07-10 (x86_64-unknown-linux)
And this version of ssh on the server:
OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010
The message is actually printed by shell, in this case tcsh.
You can use
strings /usr/bin/tcsh | grep 'no access to tty'
to ensure that it belongs to tcsh itself.
It is related to ssh only very loosely, ie ssh in this case is just the trigger, not the cause.
You should either change your approach and not use HERE DOCUMENT. Instead place executable custom_script into /path/custom_script and run it via ssh.
# this will work
ssh user#dest '/path/custom_script'
Or, just run complex command as a oneliner.
# this will work as well
ssh user#dest "cd cs4400/$dest;gcc -o $efile $file;./$efile"
On OS X, I solved a similar problem (for script provisioning on Vagrant) with ssh -t -t (note that -t comes twice).
Advice based on the ssh BSD man page:
-T Disable pseudo-terminal allocation.
-t Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can
be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.
If running tcsh is not important for you, specify a different shell and it will work:
ssh -T user#server bash << EOF
cd cs4400/$dest
gcc -o $efile $file
./$efile
EOF

Execute Remote Perl Script on a Windows Box from a Linux Box

We recently got SSH setup on our Windows boxes so we could eliminate the need for disc mounts on our Linux machines. We are using Pentaho and I am writing a shell script that will, from a Linux box, SSH into the Windows box and execute a perl script.
I have able to write in a way to SSH into the windows box and switch to the directory that holds the Perl scripts that I need to execute, I just can't figure out how to actually execute them.
This is what I have:
#!/bin/sh
ssh -t xxxxx#xxxxx "cd /path/to/script/ /path/to/perl.exe HelloWorld.pl"
I have also tried:
#!/bin/sh
ssh -t xxxxx#xxxxx "cd /path/to/directory/with/perl/script" \
"/path/to/perl.exe HelloWorld.pl"
Both attempts result in a short delay and then a "disconnected from xxxxx" and the perl does not run. I can do all of these steps manually through a shell, but can't seem to get them working in script form. As a note, the only way I've been able to execute the perl scripts is if have the shell in the directory the perl script is in.
You need to use either a semi colon to end your statements, or execute with one statement.
try the following:
ssh xxxxx#xxxxx "cd /path/to/script/; /path/to/perl.exe HelloWorld.pl"
or:
ssh xxxxx#xxxxx "/path/to/perl.exe /path/to/script/HelloWorld.pl"
In the Windows command shell, you can use && like in a Unix-shell. If you expect the first command to succeed,
ssh -t xxxxx#xxxxx "cd /path/to/script/ && /path/to/perl.exe HelloWorld.pl"
will work.

Resources