LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices



Reply
 
Search this Thread
Old 06-29-2010, 07:52 PM   #1
buee
Member
 
Registered: May 2009
Posts: 81

Rep: Reputation: 16
Passing commands through an SSH shell in a bash script


I have a txt file with a bunch of commands. Here is the file"

Code:
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.44 dst-port=1-65535 comment="Baer NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.45 dst-port=1-65535 comment="Watson NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.46 dst-port=1-65535 comment="Watson NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.49 dst-port=1-65535 comment="Smith NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.50 dst-port=1-65535 comment="Johnson NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.51 dst-port=1-65535 comment="Johnson NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.55 dst-port=1-65535 comment="Smith NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.56 dst-port=1-65535 comment="Smith NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.58 dst-port=1-65535 comment="Smith NONPAYER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=81 protocol=tcp src-address=192.168.10.47 dst-port=1-65535 comment="Watson TORRENTER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=81 protocol=tcp src-address=192.168.10.48 dst-port=1-65535 comment="Watson TORRENTER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=81 protocol=tcp src-address=192.168.10.52 dst-port=1-65535 comment="Johnson TORRENTER"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=82 protocol=tcp src-address=192.168.10.53 dst-port=1-65535 comment="Johnson SPEED JUNKIE"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=82 protocol=tcp src-address=192.168.10.54 dst-port=1-65535 comment="Smith SPEED JUNKIE"'
'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=82 protocol=tcp src-address=192.168.10.57 dst-port=1-65535 comment="Smith SPEED JUNKIE"'
So, the portion of the script that throws these out there is:

Code:
cat /media/32GB/MikroTik/firewall_rules.txt | while read line; do
(ssh admin@192.254.1.1 $line)
done
I've tried wrapping the ssh command in ", `, ', ( & ), I always get:

Code:
expected command name (line 1 column 1)
What's the proper way to do this do while loop so it will pass these commands?

I have already got the key authentication set up and have tested it by passing

Code:
ssh admin@192.254.1.1 '/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=81 protocol=tcp src-address=192.168.10.52 dst-port=1-65535 comment="Johnson TORRENTER"'
And that works fine.
 
Old 06-29-2010, 09:20 PM   #2
adamben
Member
 
Registered: Feb 2007
Distribution: slackware,gentoo,ubuntu
Posts: 50

Rep: Reputation: 17
How about this?

Code:
cat commands.txt | while read x; do echo $( ssh regularuser@remotehostnameorip.domain "sudo $x" & )  ; done

Last edited by adamben; 06-29-2010 at 09:22 PM.
 
Old 06-29-2010, 09:42 PM   #3
buee
Member
 
Registered: May 2009
Posts: 81

Original Poster
Rep: Reputation: 16
Quote:
Originally Posted by adamben View Post
How about this?

Code:
cat commands.txt | while read x; do echo $( ssh regularuser@remotehostnameorip.domain "sudo $x" & )  ; done
I had to modify it a little bit because I'm not going to a linux box with a conventional superuser. I'm going to a MikroTik router. The PITA here is not with the router though because executing the commands works fine.

Here what I ended up using, still getting the same error:

Code:
cat /media/32GB/MikroTik/firewall_rules.txt | while read line; do
echo $( ssh admin@192.254.1.1 $line & ) ;
done
I tried putting $line in quotes too.

The really confusing part is that I call in another script before this that does essentially the same thing, it works, but uses:

Code:
`ssh admin@192.254.1.1 '/ip firewall nat remove 6'`
The only difference I'm seeing is there is no variable in the shorter version.
 
Old 06-30-2010, 12:17 AM   #4
chrism01
Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.6, Centos 5.10
Posts: 16,324

Rep: Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041Reputation: 2041
I suspect that the first level of parsing by the shell strips off the leading/trailing single quotes from the file recs. Try escaping them thus
Code:
\'/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=81 protocol=tcp src-address=192.168.10.52 dst-port=1-65535 comment="Johnson TORRENTER"\'
Try one line manually first....
Also, to see what's really happening, try

set -vx

at the top of the script.

Last edited by chrism01; 06-30-2010 at 07:37 AM.
 
Old 06-30-2010, 07:18 AM   #5
geoff_f
Member
 
Registered: May 2003
Location: Canberra, Australia
Distribution: openSUSE 11.3
Posts: 445

Rep: Reputation: 31
Try:
Code:
ssh admin@192.254.1.1 < /media/32GB/MikroTik/firewall_rules.txt
[edit] With 'firewall_rules.txt' formatted as you originally had it (without backslashes). It might even work without the single quotes.

Last edited by geoff_f; 06-30-2010 at 08:08 AM.
 
Old 06-30-2010, 08:04 AM   #6
adamben
Member
 
Registered: Feb 2007
Distribution: slackware,gentoo,ubuntu
Posts: 50

Rep: Reputation: 17
I agree with the guru, if you can mod the input file and put in escapes/etc. might work ok for you.

Can also try an eval version:

cat cmds.txt | while read i; do echo $( eval "ssh remoteuser@host.domain ""$i" & ); done
 
Old 06-30-2010, 08:26 AM   #7
gsal
LQ Newbie
 
Registered: Jul 2006
Posts: 7

Rep: Reputation: 0
if you are going to be explicitly typing all those commands, why don't you simply add the ssh part to them too?

ssh admin@192.254.1.1 '/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.44 dst-port=1-65535 comment="Baer NONPAYER"'
ssh ad,om@192.254.1.1 '/ip firewall nat add chain=dstnat action=dst-nat to-addresses=10.0.0.25 to-ports=80 protocol=tcp src-address=192.168.10.45 dst-port=1-65535 comment="Watson NONPAYER"'

That way you don't have to worry about 'cat' or re-direction or one too many parsing/evaluations by previous shell interpretation, etc.

You would of course have to make the file executable and add the '#!/bin/bash' at the beginning of the file and that's it. Then, you simply run such file from the command line.

Last edited by gsal; 06-30-2010 at 08:49 AM.
 
Old 06-30-2010, 09:28 AM   #8
pheonix7117
LQ Newbie
 
Registered: Apr 2006
Posts: 3

Rep: Reputation: 0
Or you could scp the file to the remote server, and just run it with bash. This also negates the need to make multiple ssh connections within a short span of time. Just two: one to copy the file with the list of commands, and a second to ssh in to run the file.
 
Old 06-30-2010, 09:57 AM   #9
dannybpng
Member
 
Registered: Sep 2003
Location: USA
Distribution: Fedora 20
Posts: 60

Rep: Reputation: 19
The single quotes are messing it up, because it thinks the whole line is the name of the command. Remove the single quotes from each line and type the following command.

ssh admin@192.254.1.1 < /media/32GB/MikroTik/firewall_rules.txt
 
Old 06-30-2010, 08:02 PM   #10
Swynndla2
LQ Newbie
 
Registered: Sep 2008
Posts: 2

Rep: Reputation: 0
I agree that the single quotes need to be removed from the txt file.

Then, as suggested, this should work:
Code:
ssh admin@192.254.1.1 < /media/32GB/MikroTik/firewall_rules.txt
and then also this should work:
Code:
cat /media/32GB/MikroTik/firewall_rules.txt | while read line; do
echo $( ssh admin@192.254.1.1 $line & )
done
or nicer:
Code:
cat /media/32GB/MikroTik/firewall_rules.txt | while read line; do
ssh -n admin@192.254.1.1 $line
done
 
1 members found this post helpful.
Old 06-30-2010, 08:17 PM   #11
buee
Member
 
Registered: May 2009
Posts: 81

Original Poster
Rep: Reputation: 16
Well, I spent a lot of time redoing this script. I've taken out all references to awk altogether and combined all of it in to one enormous script. A few bugs worked out thanks to the replies I've received here. Using ssh admin@192.254.1.1 < /media/32GB/MikroTik/firewall_scripts is awesome because it literally cut the run time of this script down to 1/100 of what it was. I've tested it, and this appears to be working just fine:

Code:
#!/bin/bash

path=/media/32GB/MikroTik
webaddress=10.0.0.11
bport=81
tport=82
sport=83

#Removing Old Firewall Rules
number=$(wc -l $path/firewall_rules.txt | cut -f1 -d' ')

number=$(($number+4))

rm -f $path/firewall_rules.txt

i=5

while [ $i -lt $number ]; do
echo -ne "$i," >> $path/temporary.txt && ((i++))
done

echo -ne "$i" >> $path/temporary.txt

rules=$(cat $path/temporary.txt)

ssh admin@192.254.1.1 "/ip firewall nat remove $rules"

rm -f $path/temporary.txt

#Making new rules
#Billing
zero=0
h=$(wc -l $path/CustomerUnpaid.txt | cut -f1 -d' ')

while [ $zero -lt $h ]; do
((zero++))
name=$(cat $path/CustomerUnpaid.txt | head -$zero | tail -1 | cut -f1)
ip=$(cat $path/CustomerUnpaid.txt | head -$zero | tail -1 | cut -f2)
echo "/ip firewall nat add chain=dstnat action=dst-nat to-addresses="$webaddress" to-ports="$bport" protocol=tcp src-address="$ip" dst-port=1-65535 comment=\""$name" NONPAYER\"" >> $path/firewall_rules.txt
done

rm -f $path/Name.txt $path/IP.txt


#Torrent
zero=0
h=$(wc -l $path/Torrenters.txt | cut -f1 -d' ')

while [ $zero -lt $h ]; do
((zero++))
name=$(cat $path/Torrenters.txt | head -$zero | tail -1 | cut -f1)
ip=$(cat $path/Torrenters.txt | head -$zero | tail -1 | cut -f2)
echo "/ip firewall nat add chain=dstnat action=dst-nat to-addresses="$webaddress" to-ports="$tport" protocol=tcp src-address="$ip" dst-port=1-65535 comment=\""$name" TORRENT HOUND\"" >> $path/firewall_rules.txt
done

rm -f $path/Name.txt $path/IP.txt

#Speed Junkies
zero=0
h=$(wc -l $path/SpeedTests.txt | cut -f1 -d' ')

while [ $zero -lt $h ]; do
((zero++))
name=$(cat $path/SpeedTests.txt | head -$zero | tail -1 | cut -f1)
ip=$(cat $path/SpeedTests.txt | head -$zero | tail -1 | cut -f2)
echo "/ip firewall nat add chain=dstnat action=dst-nat to-addresses="$webaddress" to-ports="$sport" protocol=tcp src-address="$ip" dst-port=1-65535 comment=\""$name" SPEED JUNKIE\"" >> $path/firewall_rules.txt
done

rm -f $path/Name.txt $path/IP.txt

#Applying new rules
ssh admin@192.254.1.1 < $path/firewall_rules.txt

exit 0
Thanks to everyone who replied.
 
Old 06-30-2010, 11:23 PM   #12
simon.sweetman
Member
 
Registered: Mar 2009
Posts: 32

Rep: Reputation: 22
You could consider some further improvements below (Uses IFS= and read to remove cat, head and tail usage, removes usage of temp files, etc.)

Are Name.txt and ip.txt just leftover temp files?

Code:
#!/bin/bash
path=/media/32GB/MikroTik

webaddress=10.0.0.11
bport=81
tport=82
sport=83

TAB=$(printf '\t')

#Removing Old Firewall Rules
number=$(wc -l $path/firewall_rules.txt)
number=${number%% *}
number=$(($number+4))

for((i=5; i<$number; i++))
do
    rules=$rules$i,
done
rules=$rules$i

ssh admin@192.254.1.1 "/ip firewall nat remove $rules"

rm -f $path/firewall_rules.txt

#Making new rules
#Billing

OLDIFS=$IFS
IFS=$TAB
while read name ip ignore
do
    echo "/ip firewall nat add chain=dstnat action=dst-nat to-addresses="$webaddress" to-ports="$bport" protocol=tcp src-address="$ip" dst-port=1-65535 comment=\""$name" NONPAYER\"" >> $path/firewall_rules.txt
done < $path/CustomerUnpaid.txt
IFS=$OLDIFS

#Torrent
IFS=$TAB
while read name ip ignore
do
    echo "/ip firewall nat add chain=dstnat action=dst-nat to-addresses="$webaddress" to-ports="$tport" protocol=tcp src-address="$ip" dst-port=1-65535 comment=\""$name" TORRENT HOUND\"" >> $path/firewall_rules.txt
done < $path/Torrenters.txt
IFS=$OLDIFS

#Speed Junkies
IFS=$TAB
while read name ip ignore
do
    echo "/ip firewall nat add chain=dstnat action=dst-nat to-addresses="$webaddress" to-ports="$sport" protocol=tcp src-address="$ip" dst-port=1-65535 comment=\""$name" SPEED JUNKIE\"" >> $path/firewall_rules.txt
done < $path/SpeedTests.txt
IFS=$OLDIFS

rm -f $path/Name.txt $path/IP.txt

#Applying new rules
ssh admin@192.254.1.1 < $path/firewall_rules.txt

exit 0
 
Old 07-01-2010, 02:28 AM   #13
geoff_f
Member
 
Registered: May 2003
Location: Canberra, Australia
Distribution: openSUSE 11.3
Posts: 445

Rep: Reputation: 31
Just a comment for the benefit of those suggesting while..do..done loops in this situation.

The firewall_rules.txt file is a list of commands needed to be executed in the remote environment, separated by Linefeed characters. When issued by this command:
Code:
ssh admin@192.254.1.1 < /media/32GB/MikroTik/firewall_rules.txt
it's the same as sitting at a terminal in the remote environment, typing in each line, and hitting Enter after each one. Therefore, that one command - in the local environment - issues many commands in the remote environment, without any need to loop through variables, etc. That's the reason this method is so efficient. Program response time across a network is many times slower than in the local environment (with RAM, hard disks, etc), which makes it so much faster (in time) when using the more efficient (in programming) method when communicating across a network.

Think upon that, and marvel at the awesome power of the shell.
 
  


Reply

Tags
bash, script, ssh


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
passing variable from bash to perl in a bash script quadmore Programming 6 02-21-2011 05:11 AM
[SOLVED] passing commands as arguments to functions in bash script mastahyeti Linux - General 3 05-31-2010 07:19 PM
Java: passing linux shell commands borgy_t Programming 3 04-19-2005 04:50 AM
Passing commands via ssh Comatose51 Linux - Security 1 04-13-2005 05:31 PM
shell scripting -- passing commands mehesque Linux - General 4 06-25-2004 11:28 AM


All times are GMT -5. The time now is 08:17 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration