Bash: executing a command based on organized output

Just learning scripting. I need to remove duplicate managed printers using lpadmin. I have the following script (it's rough and probably a better way to do it) that returns the values as IP (column 1) Printer Name (column 2).command:
lpstat -v | grep -E '192.168.*.20|192.168.*.21|192.168.*.22|192.168.*.23|192.168.*.24|192.168.*.25|192.168.*.90' | awk '{print $4,$3"/"}' | sort | awk -F "/" '{print $3,$4}'

 output:
192.168.10.20  MX4100N:
192.168.24.21  AR208D:
 192.168.24.22  mcx_5:
192.168.24.22  mcx_8:
192.168.24.22   M620N:
192.168.24.23  mcx_6:
192.168.24.23  M363N1:
 192.168.24.24  mcx_7:
192.168.24.24  M363N2:
 192.168.24.25  M363N3:
192.168.24.90  mcx_0:
 192.168.24.90  mcx_1:
192.168.24.90  mcx_2:
192.168.24.90   mcx_3:
192.168.24.90  mcx_4:

What I would like to do is set up a loop that tells lpadmin to remove duplicate IP based printers based on printer name. I want to keep the highest value where they are mcx_* (managed printer) and if there is a named printer with the same IP keep the mcx printer. So from the above output I want to send the following commands to clean up the machine.lpadmin -x M620N
lpadmin -x M363N1
lpadmin -x M363N2
lpadmin -x mcx_0
lpadmin -x mcx_1
lpadmin -x mcx_2
lpadmin -x mcx_3
lpadmin -x mcx_5
This would result in the following list of installed printers. 192.168.10.20 MX4100N:
192.168.24.21 AR208D:
192.168.24.22 mcx_8:
192.168.24.23 mcx_6:
192.168.24.24 mcx_7:
192.168.24.25 M363N3:
192.168.24.90 mcx_4:
I was thinking of assigning the output to an array and using a loop but can't wrap my brain around how to accomplish this. Does this make sense? I think I'm confusing myself trying to explain it!

sort -r |awk '{if(++a[$1]==1){print >"installed_printers"}else {print "Ipadmin -x "$2 > "clean_up"}}' 
1 Like

Thank you yinyuemi! So output goes to the files and then I can chmod +x "clean_up" and run it. This is exactly what I needed to do. A few questions in follow up.
Can you break down your code or point me to somewhere I can look to get an explanation? I have been perusing forums and how-to's and googling and had no luck. I was obviously looking for the wrong thing.

Could this be done without creating files? It's not a huge deal. I can add a few lines for clean-up at the end of the script to remove these. It's really more of a "can it be done" question.
Thanks again!

first code "

sort -r

"

echo "192.168.10.20 MX4100N:
192.168.24.21 AR208D:
192.168.24.22 mcx_5:
192.168.24.22 mcx_8:
192.168.24.22 M620N:
192.168.24.23 mcx_6:
192.168.24.23 M363N1:
192.168.24.24 mcx_7:
192.168.24.24 M363N2:
192.168.24.25 M363N3:
192.168.24.90 mcx_0:
192.168.24.90 mcx_1:
192.168.24.90 mcx_2:
192.168.24.90 mcx_3:
192.168.24.90 mcx_4:" |sort -r
192.168.24.90 mcx_4:
192.168.24.90 mcx_3:
192.168.24.90 mcx_2:
192.168.24.90 mcx_1:
192.168.24.90 mcx_0:
192.168.24.25 M363N3:
192.168.24.24 mcx_7:
192.168.24.24 M363N2:
192.168.24.23 mcx_6:
192.168.24.23 M363N1:
192.168.24.22 mcx_8:
192.168.24.22 mcx_5:
192.168.24.22 M620N:
192.168.24.21 AR208D:
192.168.10.20 MX4100N:

After sorted reversely, you can see the red lines has the "highest value", also it is the first one if the IP has duplicated other ones. However, it might only worked for your exampled data, since the data of sec. column was sorted based on the ALPHA characters, that means if the first letter after "M", like N,O..., the first one of one certain IP would not be "max..", so the results could not be correct.

The awk code:

awk '{
if(++a[$1]==1) ## ++a[$1]==1 means the first time of apprearance of $1, a[$1] is a array.
{print >"installed_printers"} ## they're printed as "installed_printers" file
else 
{print "Ipadmin -x "$2 > "clean_up"} ## else, printed as "clean_up" file
}'

if any problem, let me know. Sorry for my bad english:)

1 Like

Awesome job explaining so not to worry about your english. This helps greatly and will come in handy for future projects I'm sure. Thank you so much for your help. The task of dealing with duplicate printers just got a whole lot easier.

You could also replace the egrep and 2 awks above with this:

lpstat -v | awk ' $4 ~ /^192\.168\.[0-9]+\.(2[0-5]|90)$/ { print $4,$3 }' | sort -r | ...yinyuemi's awk script...

if field 4 matches <begining of string> 192 <dot> 168 <dot> <one-or-more-digits> <dot> <either "2<zero thru 5>" or "90"> <end of string>
then print field 4 <space> field 3

1 Like

Thanks Chubler_XL. That shortens things up. I figured there was an easier/better way to get what I needed. I'm using a lot of pipes until I figure out the proper way to do things. I'm getting a lot of good information from this site and the folks here.
Thanks again.