[SOLVED] Bash - While Loop reading from two lists simultaneously - nested while loop
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
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.
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.
Bash - While Loop reading from two lists simultaneously - nested while loop
Hi,
I use while loops to make configuration changes on network devices all the time, so I am pretty familiar with while loops, but I can't seem to get this to work.
I need to make configuration changes in separate parts of the command tree on the multiple devices. This basically requires a while loop to read from two separate lists of commands and echo alternating output from those lists. I usually use expect, but in this case all I need is to echo some command output to a file and then paste it into the terminal. Here is an example:
The command output starts like this:
subnet 71.1.24.0/21 name dhcp03
range 71.1.24.2 71.1.31.254
subnet 71.50.128.0/21 name dhcp02
range 71.50.128.2 71.50.135.254
subnet 184.3.144.0/21 name dhcp01
range 184.3.144.2 184.3.151.254
I need to add "threshold falling 100 log" to the end of the lines that start with "range". However, in order to get to that point, you have to enter the lines that start with "subnet" first. So, I created two lists, similar to the following:
subnet 71.1.24.0/21 name dhcp03
subnet 71.50.128.0/21 name dhcp02
subnet 184.3.144.0/21 name dhcp01
range 71.1.24.2 71.1.31.254
range 71.50.128.2 71.50.135.254
range 184.3.144.2 184.3.151.254
I would think I would need to crete a nested while loop to do this, but I can't get it to work at all. Here is what I have so far:
#!/bin/bash
# dhcpbugchange.sh
outer=1 # Set outer loop counter.
# Beginning of outer loop.
cat subnets.txt | while read subnet
do
echo "$subnet"
inner=1 # Reset inner loop counter.
# Beginning of inner loop.
cat ranges.txt | while read range
do
echo "$range threshold falling 100 log"
let "inner+=1" # Increment inner loop counter.
done
# End of inner loop.
let "outer+=1" # Increment outer loop counter.
echo # Space between output blocks in pass of outer loop.
done
# End of outer loop.
exit 0
I chmod +x and chmod 777 and this is what I get:
bash-3.00$ ./dhcpbugchanges.sh
: bad interpreter: No such file or directory
bash-3.00$
allen@tornado:~$ paste -d'\n' subnets.txt ranges.txt | sed '/^range /s/$/ threshold falling 100 log/'
subnet 71.1.24.0/21 name dhcp03
range 71.1.24.2 71.1.31.254 threshold falling 100 log
subnet 71.50.128.0/21 name dhcp02
range 71.50.128.2 71.50.135.254 threshold falling 100 log
subnet 184.3.144.0/21 name dhcp01
range 184.3.144.2 184.3.151.254 threshold falling 100 log
Code:
allen@tornado:~$ sed 's/$/ threshold falling 100 log/' ranges.txt | paste -d'\n' subnets.txt -
subnet 71.1.24.0/21 name dhcp03
range 71.1.24.2 71.1.31.254 threshold falling 100 log
subnet 71.50.128.0/21 name dhcp02
range 71.50.128.2 71.50.135.254 threshold falling 100 log
subnet 184.3.144.0/21 name dhcp01
range 184.3.144.2 184.3.151.254 threshold falling 100 log
However, I'm one of those "give a man a fish and he'll eat for a day, teach a man to fish and he'll eat for the rest of his life" type of people. I like to learn why I'm doing what I'm doing instead of just cutting and pasting things so that I can potentially help others too. I believe your syntax says the following:
Says: "Use the paste command, using a line feed (\n) as a delimiter for the files "subnets.txt" and "ranges.txt". Pipe the output to sed. With sed, anything starting (hence the ^) with the word "range" needs to have something added to the end (hence the $) of the string (hence the usage of the s option). That "something" is "threshold falling 100 log".
Says: Use sed to add something to the end (hence the $) of the string (hence the usage of the s option) in the file "ranges.txt". That something is "threshold falling 100 log". Pipe the output to the paste command, using a new line feed (\n) as the delimiter (hence the -d option) for the file subnets.txt. However, this is where it gets fuzzy. I'm assuming that the - tells sed to somehow start with the output of the subnets.txt file first? But, I tried removing the hyphen to see what happened and it didn't print the ranges.txt output at all?
Thanks in advance!
Last edited by wolverene13; 09-10-2011 at 09:13 PM.
Reason: Found the answers to most of my follow up questions by playing with the command, yet I still had one more question unanswered
However, I'm one of those "give a man a fish and he'll eat for a day, teach a man to fish and he'll eat for the rest of his life" type of people. I like to learn why I'm doing what I'm doing instead of just cutting and pasting things so that I can potentially help others too. Can you clarify what s/$/, ^range, and \n do? According to the man page, it looks like -d designates a delimiter, so I'm guessing \n is referencing a new line? If that's the case, can you use \r too? Does s/$/ essentially say "add the following to the end of the string"? And ^range appears to say "anything beginning with the word "range", is that right? I always thought that ^ meant the inverse of whatever your string is, but is it different with sed?
"s" is the command to call in sed, and "/^range /" is an address specification: This means "s" will only be executed on lines that start ("^") with "range ". In the second version "s" is unconditionally called because all lines are assumed to start with "range ". '\n' is considered a newline by most of the standard command-line utilities. (One notable exception is cut, which doesn't seem to accept any escaped characters.) "s" requires 2 arguments: The pattern and the replacement. The character right after "s" is the separator ("/"). The pattern is "$", or "the end of the line" (which all lines have), which is replaced by " threshold falling 100 log". Note that the spaces I used are not separators; they're literal text.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.