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 |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
 |
06-29-2010, 06:52 PM
|
#1
|
Member
Registered: May 2009
Posts: 81
Rep:
|
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.
|
|
|
06-29-2010, 08:20 PM
|
#2
|
Member
Registered: Feb 2007
Distribution: slackware,gentoo,ubuntu
Posts: 50
Rep:
|
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 08:22 PM.
|
|
|
06-29-2010, 08:42 PM
|
#3
|
Member
Registered: May 2009
Posts: 81
Original Poster
Rep:
|
Quote:
Originally Posted by adamben
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.
|
|
|
06-29-2010, 11:17 PM
|
#4
|
LQ Guru
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.x
Posts: 18,434
|
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 06:37 AM.
|
|
|
06-30-2010, 06:18 AM
|
#5
|
Member
Registered: May 2003
Location: Canberra, Australia
Distribution: openSUSE 11.3
Posts: 445
Rep:
|
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 07:08 AM.
|
|
|
06-30-2010, 07:04 AM
|
#6
|
Member
Registered: Feb 2007
Distribution: slackware,gentoo,ubuntu
Posts: 50
Rep:
|
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
|
|
|
06-30-2010, 07:26 AM
|
#7
|
LQ Newbie
Registered: Jul 2006
Posts: 7
Rep:
|
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 07:49 AM.
|
|
|
06-30-2010, 08:28 AM
|
#8
|
LQ Newbie
Registered: Apr 2006
Posts: 3
Rep:
|
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.
|
|
|
06-30-2010, 08:57 AM
|
#9
|
Member
Registered: Sep 2003
Location: USA
Distribution: Fedora 35
Posts: 79
Rep:
|
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
|
|
|
06-30-2010, 07:02 PM
|
#10
|
LQ Newbie
Registered: Sep 2008
Posts: 2
Rep:
|
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.
|
06-30-2010, 07:17 PM
|
#11
|
Member
Registered: May 2009
Posts: 81
Original Poster
Rep:
|
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.
|
|
|
06-30-2010, 10:23 PM
|
#12
|
Member
Registered: Mar 2009
Posts: 32
Rep:
|
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
|
|
|
07-01-2010, 01:28 AM
|
#13
|
Member
Registered: May 2003
Location: Canberra, Australia
Distribution: openSUSE 11.3
Posts: 445
Rep:
|
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.
|
|
|
All times are GMT -5. The time now is 05:35 AM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|