I'm trying to parse multipath output on linux for a script I am writing, and I can't quite find the correct SED or AWK syntax to get it how I want it. I've been browsing various sites and stackoverflow examples without much luck.
I want to find a way to make:
temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN
[size=20G]
2:0:0:4 sde 8:64 [active][ready]
1:0:0:4 sdm 8:192 [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN
[size=5.0G]
2:0:0:3 sdd 8:48 [active][ready]
1:0:0:3 sdl 8:176 [active][ready]
look like:
temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 2:0:0:4 sde 8:64 active][ready]
temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 1:0:0:4 sdm 8:192 [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 2:0:0:3 sdd 8:48 [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 1:0:0:3 sdl 8:176 [active][ready]
** Edit Ok, so making this even harder, I have found multipath configurations without Netapp's default settings. This makes it so that NETAPP,LUN is not guarenteed to be on the line. What I've started to do:
/sbin/multipath -ll | grep -v "round-robin"| sed 's/\[feat.*//g' | sed ':a; $!N;s/\n\([^\n]*\[size\)/ \1/;ta;P;D'
which puts size on the main line to give me something else to match:
360a98000572d4d2d5834664e68323436 dm-6 NETAPP,LUN [size=50G]
\_ 1:0:0:0 sda 8:0 [active][ready]
360a98000572d4d2d5834664e68395951 dm-7 NETAPP,LUN [size=275G]
\_ 1:0:0:7 sdb 8:16 [active][ready]
However I can't get any of the examples below to match "G[$" (I know that I will need to have another line for T if there are any terrabyte volumes) and give me the correct output.
Thanks for everyones suggestions below **End Edit
I know how to clean up spacing, so I will do that after I can get the output correct. The Lines that will begin the multipath information all end with "LUN". The servers can have anywhere from one to 8 paths under each LUN line (the sdx devices). The part before the "()" can either be text (an alias), or numeric.
One way:
Content of script.awk
:
$1 ~ /^([[:digit:]]:){3}[[:digit:]]$/ {
printf "%s %s\n", line, $0;
next;
}
##$1 ~ /temp|redo/ {
$0 ~ /LUN$/ {
getline l;
line = $0 " " l;
}
Assuming infile
with the content of the question, run the script like:
awk -f script.awk infile
With following output:
temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 2:0:0:4 sde 8:64 [active][ready]
temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 1:0:0:4 sdm 8:192 [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 2:0:0:3 sdd 8:48 [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 1:0:0:3 sdl 8:176 [active][ready]
I don't know the exact specification of input, but this one-liner may help you:
awk '{if (/LUN$/){ prefix = $0; getline; prefix = prefix " " $0 } else {print prefix, $0} }'
/LUN$/
regex)getline
and implicit concatenation operator)prefix
PS: you may need additional line filtering, which shouldn't be hard, just add another if
in the else
branch.
This might work for you (GNU sed):
sed '/LUN$/{N;y/\n/ /;h;d};G;s/^\([^\n]*\)\n\(.*\)/\2 \1/' file
Explanation:
/LUN$/{N;y/\n/ /;h;d}
For lines ending in LUN
append a newline and then the following line to the pattern space (PS), replace the newline by a space, store the PS in the hold space (HS) and then delete the PS and star the next cycle.G
for all other lines (path lines), append a newline followed by the contents of the HS in the PS.s/^\([^\n]*\)\n\(.*\)/\2 \1/
swap anything upto the first newline with anything following it and replace the newline by a space i.e. append the header information to the path line.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With