Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using sed or awk to parse multipath output

Tags:

linux

bash

sed

awk

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.

like image 951
Unix_Linux_guy Avatar asked Aug 22 '12 19:08

Unix_Linux_guy


3 Answers

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]
like image 155
Birei Avatar answered Sep 27 '22 22:09

Birei


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} }'

  1. It checks if current line ends with LUN(by matching it against the /LUN$/ regex)
  2. If there is match, it concatenates current line with the next(using getline and implicit concatenation operator)
  3. If there is no match, it outputs current record along with prefix

PS: you may need additional line filtering, which shouldn't be hard, just add another if in the else branch.

like image 26
Alexander Putilin Avatar answered Sep 27 '22 22:09

Alexander Putilin


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.
like image 21
potong Avatar answered Sep 28 '22 00:09

potong