Bash, running script with parameters from local to SSH HOST. [duplicate] - bash

I would like to expand a little more on "Bash - How to pass arguments to a script that is read via standard input" post.
I would like to create a script that takes standard input and runs it remotely while passing arguments to it.
Simplified contents of the script that I'm building:
ssh server_name bash <&0
How do I take the following method of accepting arguments and apply it to my script?
cat script.sh | bash /dev/stdin arguments
Maybe I am doing this incorrectly, please provide alternate solutions as well.

Try this:
cat script.sh | ssh some_server bash -s - <arguments>

ssh shouldn't make a difference:
$ cat do_x
#!/bin/sh
arg1=$1
arg2=$2
all_cmdline=$*
read arg2_from_stdin
echo "arg1: ${arg1}"
echo "arg2: ${arg2}"
echo "all_cmdline: ${all_cmdline}"
echo "arg2_from_stdin: ${arg2_from_stdin}"
$ echo 'a b c' > some_file
$ ./do_x 1 2 3 4 5 < some_file
arg1: 1
arg2: 2
all_cmdline: 1 2 3 4 5
arg2_from_stdin: a b c
$ ssh some-server do_x 1 2 3 4 5 < some_file
arg1: 1
arg2: 2
all_cmdline: 1 2 3 4 5
arg2_from_stdin: a b c

This variant on ccarton's answer also seems to work well:
ssh some_server bash -s - < script.sh <arguments>

Related

How to choose any number of elements through user input in bash?

I have created this script which currently is taking a list of arguments from command line but what I want to do is let the user pass any numerical value which would then start executing the loop for number of the times the user has asked. The script is run in the following way for example ./testing.sh launch 1 2 3 4 5 6 7 8. How can I make a user pass a numerical value like 8 which would then loop over the IPs instead of doing 1 2 3 4 5 6 7 8. Also is there a better way to deal with so many IPs that I have passed in the script like for example map them and read them from a file.
#!/bin/bash
#!/usr/bin/expect
ips=()
tarts=()
launch_tarts () {
local tart=$1
local ip=${ip[tart]}
echo " ---- Launching Tart $1 ---- "
sshpass -p "tart123" ssh -Y -X -L 5900:$ip:5901 tarts#$ip <<EOF1
export DISPLAY=:1
gnome-terminal -e "bash -c \"pwd; cd /home/tarts; pwd; ./launch_tarts.sh exec bash\""
exit
EOF1
}
kill_tarts () {
local tart=$1
local ip=${ip[tart]}
echo " ---- Killing Tart $1 ---- "
sshpass -p "tart123" ssh -tt -o StrictHostKeyChecking=no tarts#$ip <<EOF1
. ./tartsenvironfile.8.1.1.0
nohup yes | kill_tarts mcgdrv &
nohup yes | kill_tarts server &
pkill -f traf
pkill -f terminal-server
exit
EOF1
}
tarts_setup () {
local tart=$1
local ip=${ip[tart]}
echo " ---- Setting-Up Tart $1 ---- "
sshpass -p "root12" ssh -tt -o StrictHostKeyChecking=no root#$ip <<EOF1
pwd
nohup yes | /etc/rc.d/init.d/lifconfig
su tarts
nohup yes | vncserver
sleep 10
exit
exit
EOF1
}
ip[1]=10.171.0.10
ip[2]=10.171.0.11
ip[3]=10.171.0.12
ip[4]=10.171.0.13
ip[5]=10.171.0.14
ip[6]=10.171.0.15
ip[7]=10.171.0.16
ip[8]=10.171.0.17
ip[9]=10.171.0.18
ip[10]=10.171.0.19
ip[11]=10.171.0.20
ip[12]=10.171.0.21
ip[13]=10.171.0.100
ip[14]=10.171.0.101
ip[15]=10.171.0.102
ip[16]=10.171.0.103
ip[17]=10.171.0.104
ip[18]=10.171.0.105
ip[19]=10.171.0.106
ip[20]=10.171.0.107
case $1 in
kill) function=kill_tarts;;
launch) function=launch_tarts;;
setup) function=tarts_setup;;
*) exit 1;;
esac
shift
for tart in "$#"; do
($function $tart) &
ips+=(${ip[tart]})
# echo $ips
tarts+=(${tart[#]})
# echo $tarts
done
wait
Can someone guide please?
Try changing the bottom loop to: for ((tart=1; tart<=$2; tart++)), then use like: ./testing.sh launch 8.
You you can put multiple variable declarations on one line, so you could split the ip list in to two or three columns.
Or use mapfile: mapfile -t ip < ip-list. You will need to use tart - 1 for the array index though, like "${ip[tart-1]}", as the array will start at 0, not 1.
You want the seq command:
for x in $(seq 5); do
echo $x
done
this will produce the output
1
2
3
4
5
Then just take the number of iterations you want as another parameter on the command line, and use that in place of the hard coded 5 in my example.
seq just generates a sequence of numbers. From the man page:
SYNOPSIS
seq [-w] [-f format] [-s string] [-t string] [first [incr]] last
DESCRIPTION
The seq utility prints a sequence of numbers, one per line >(default), from first (default 1), to near last as possible, in >increments of incr (default 1). When first is larger than last the >default incr
is -1.

SSH running sh script that works locally but not remotely

I am trying to run a script that will be called by some other software to run some parameters to get out objective values.
The script run.sh is as follows:
#!/bin/bash
set -e
ssh id#somehost '
/path/to/folder/solver arg1 arg2 arg3
res=$(</path/to/folder/res_data.txt)
echo "Final Result:"
echo "1 $res"
'
Running this file results in the following:
$ sh run.sh
OpenNN Exception: NeuralNetwork class.
void load(const std::string&) method.
Cannot load XML file ../data/neural_network.xml.
Final Result:
1 -285361 3.22136
Connection to somehost closed.
The Final Result above is from a previous output
If I run a similar script without the ssh
set -e
/path/to/folder/solver arg1 arg2 arg3
res=$(</path/to/folder/res_data.txt)
echo "Final Result:"
echo "1 $res"
Results in
$ sh run.sh 7 26 100
Final Result:
1 -285361 3.22136
$ sh run.sh 7 26 150
Final Result:
1 -421429 5.16397
Does anyone have any idea how to fix this?
Based on the comments above the solution of the error I was getting,
#!/bin/bash
set -e
ssh id#somehost '
cd /path/to/folder/
./solver '$1' '$2' '$3'
res=$(<./res_data.txt)
echo "Final Result:"
echo "1 $res"
'
I was simple enough just to add cd /path/to/folder/ and run the script from the folder it seems to work, in addition I also fixed the issue with the arguments rather than ./solver $1 $2 $3, having ./solver '$arg1' '$arg2' '$arg3' as the way to pass the inputted arguments to run on the solver.
The following output is from the corrected file above
$ sh run.sh 7 26 100
Final Result:
1 -285361 3.22136
$sh run.sh 7 26 150
Final Result:
1 -421429 5.16397

Iterate over local Map in ssh shell script

I have a testFile having two parameters separated by pipe.
vi testFile
1|A
2|B
3|C
4|D
5|E
I am creating map and running it in a for loop, below is working:
while IFS='|' read -r NUM CHAR
do
export MAP[$NUM]=$CHAR
done < testFile
for i in ${!MAP[#]}
do
echo "$i ${MAP[$i]}"
done
But when I am going ssh to any machine and running the loop, getting
./test.sh[11]: syntax error at line 20: '!' unexpected
Below is not working
ssh someUser#someHost << EOF
for i in ${!MAP[#]}
do
echo "$i ${MAP[$i]}"
done
EOF
How do I use MAP in ssh machine
NOTE testFile is not fixed file, i am creating this file from sql query which is varying at every run.
you can try this;
#!/bin/ksh
while IFS='|' read -r NUM CHAR
do
export MAP[$NUM]=$CHAR
done < testFile
for i in "${!MAP[#]}"
do
echo "$i "${MAP[$i]}""
done
ssh someUser#someHost <<EOF
eval `typeset -p MAP`
for i in "\${!MAP[#]}"
do
echo "\$i "\${MAP[\$i]}""
done
EOF
eval : evaluated server-side
typeset: to permit modifying the properties of variables.
\$ : escape a variable
Test :
$ ksh test.ksh
1 A
2 B
3 C
4 D
5 E
user#localhost's password:
1 A
2 B
3 C
4 D
5 E

Bash - How to pass arguments to a script that is read via redirected standard input

I would like to expand a little more on "Bash - How to pass arguments to a script that is read via standard input" post.
I would like to create a script that takes standard input and runs it remotely while passing arguments to it.
Simplified contents of the script that I'm building:
ssh server_name bash <&0
How do I take the following method of accepting arguments and apply it to my script?
cat script.sh | bash /dev/stdin arguments
Maybe I am doing this incorrectly, please provide alternate solutions as well.
Try this:
cat script.sh | ssh some_server bash -s - <arguments>
ssh shouldn't make a difference:
$ cat do_x
#!/bin/sh
arg1=$1
arg2=$2
all_cmdline=$*
read arg2_from_stdin
echo "arg1: ${arg1}"
echo "arg2: ${arg2}"
echo "all_cmdline: ${all_cmdline}"
echo "arg2_from_stdin: ${arg2_from_stdin}"
$ echo 'a b c' > some_file
$ ./do_x 1 2 3 4 5 < some_file
arg1: 1
arg2: 2
all_cmdline: 1 2 3 4 5
arg2_from_stdin: a b c
$ ssh some-server do_x 1 2 3 4 5 < some_file
arg1: 1
arg2: 2
all_cmdline: 1 2 3 4 5
arg2_from_stdin: a b c
This variant on ccarton's answer also seems to work well:
ssh some_server bash -s - < script.sh <arguments>

Here document as an argument to bash function

Is it possible to pass a here document as a bash function argument, and in the function have the parameter preserved as a multi-lined variable?
Something along the following lines:
function printArgs {
echo arg1="$1"
echo -n arg2=
cat <<EOF
$2
EOF
}
printArgs 17 <<EOF
18
19
EOF
or maybe:
printArgs 17 $(cat <<EOF
18
19
EOF)
I have a here document that I want to feed to ssh as the commands to execute, and the ssh session is called from a bash function.
The way to that would be possible is:
printArgs 17 "$(cat <<EOF
18
19
EOF
)"
But why would you want to use a heredoc for this? heredoc is treated as a file in the arguments so you have to (ab)use cat to get the contents of the file, why not just do something like:
print Args 17 "18
19"
Please keep in mind that it is better to make a script on the machine you want to ssh to and run that then trying some hack like this because bash will still expand variables and such in your multiline argument.
If you're not using something that will absorb standard input, then you will have to supply something that does it:
$ foo () { while read -r line; do var+=$line; done; }
$ foo <<EOF
a
b
c
EOF
Building on Ned's answer, my solution allows the function to take its input as an argument list or as a heredoc.
printArgs() (
[[ $# -gt 0 ]] && exec <<< $*
ssh -T remotehost
)
So you can do this
printArgs uname
or this
printArgs << EOF
uname
uptime
EOF
So you can use the first form for single commands and the long form for multiple commands.
xargs should do exactly what you want. It convert standard input to argument for a command (notice -0 allow to preserve newlines)
$ xargs -0 <<EOF printArgs 17
18
19
EOF
But for you special case, I suggest you to send command on standard input of ssh:
$ ssh host <<EOF
ls
EOF
One way to feed commands to ssh through a here doc and a function is as so:
#!/bin/sh
# define the function
printArgs() {
echo "$1"
ssh -T remotehost
}
# call it with a here document supplying its standard input
printArgs 17 <<EOF
uname
uptime
EOF
The results:
17
Linux remotehost 2.6.32-5-686 ...
Last login: ...
No mail.
Linux
16:46:50 up 4 days, 17:31, 0 users, load average: 0.06, 0.04, 0.01

Resources