2

I want to merge the matching pattern with awk on a Solaris system.

$ luxadm probe 
 No Network Array enclosures found in /dev/es

 Found Fibre Channel device(s): 
 Node WWN:2000000c50f1c8da Device Type:Disk device 
 Logical Path:/dev/rdsk/c1t1d0s2 
 Node WWN:2000000c50f1d9c9 Device Type:Disk device 
 Logical Path:/dev/rdsk/c1t0d0s2

Note - While I am trying with awk, it takes Only one line merging from last.

$ luxadm probe |awk '/Node/{n=$2}/Logical/{l=$2} END {print n,l}' 
 WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2

While the output expected is:

WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2
WWN:2000000c50f1c8da Path:/dev/rdsk/c1t1d0s2 
0

4 Answers 4

3

The short answer which isn't mentioned yet in awk

awk '/Node/{n=$2; getline; print n " "$2; next}' filename
  • /Node/ # Look for pattern Node and store the second field in n variable n=$2
  • getline # Move to the next line (This is where Logical line starts), print what's stored in n variable and then second field of the next line.
  • next # Stop processing current record and move to the next one.
3
  • 1
    Your codes works.. can you explain please , I wana learn.. $ luxadm probe | awk '/Node/{n=$2; getline; print n " "$2; next}' WWN:2000000c50f1c8da Path:/dev/rdsk/c1t1d0s2 WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2
    – krock1516
    Apr 11, 2015 at 11:00
  • @Costas - Your last two codes working perfectly .. Could you pleas explain ... $ luxadm probe | awk '/Node/{printf "%s ", $2}/Logical Path/{print $2}' WWN:2000000c50f1c8da Path:/dev/rdsk/c1t1d0s2 WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2 $ luxadm probe | awk '/Node/{wwn=$2}/Logical Path/{print wwn,$2}' WWN:2000000c50f1c8da Path:/dev/rdsk/c1t1d0s2 WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2
    – krock1516
    Apr 11, 2015 at 11:02
  • @Karn Well many answers here are correct. I think you just need to get your head around and see if you understand it. All answers are explained to a great extent imo. Apr 11, 2015 at 11:04
3

The reason it's faililng is because you are only printing the variables you capture once, in an END{} block. This means that only the last two will be printed. @Costas already gave you a more elegant approach, but you could also use the same logic you were trying with a small change:

awk '{ if(/Node/){
        if(length(n)){print n,l} ## if we have an n, print them
        n=$2
        }
        if(/Logical/){l=$2}
      } 
        END {print n,l}' 

Alternatively, you could use other tools:

  1. GNU grep/perl

    luxadm probe |  grep -Po '^\s*(Node|Logical)\s*\K.*?(\s|$)' file | 
        perl -lne '$. % 2 ? printf : print'
    
  2. Perl

    luxadm probe |  
      perl -ne 'chomp;if(s/.*(WWN:.*?)\s.*/$1 / || s/.*(Path:.*?)$/$1\n/){print}'
    
7
  • Still its not giving the desired as it getting only 4th field.. I am a learner so trying to fight with this puzzle with your expertise guys.. $ luxadm probe | awk -F":| " '/Node/{printf "%s ", $3":"$4}/Logical Path/{print $4}' Disk device: Disk device:
    – krock1516
    Apr 11, 2015 at 10:53
  • @Karn did you try the one (ones, now, see update) in my answer? The one you gave in the comment above will fail, yes, but is not the one I posted.
    – terdon
    Apr 11, 2015 at 10:58
  • @Karn (please answer comments in the place they were asked, I don't get pinged otherwise). I know you showed us the output of luxadm but your comment to Costas's answer mentioned "you have mail in /var/mail/root". Is that in the input? If you try these and they fail, please edit your question and include the specific error messages/output you get. That way, we can correct it.
    – terdon
    Apr 11, 2015 at 11:01
  • @terdon a great perl one! Apr 11, 2015 at 11:06
  • @terdon - my apologies, going out of the bay while answering , may be because I am a first time user on the site..Moreover I tried your code which is throwing errors .. please see below.. $ perl -ne 'chomp;if(s/.*(WWN:.*?)\s.*/$1 / || s/.*(Path:.*?)$/$1\n/){print}' ^C$ [2] + Done(2) luxadm probe | grep -Po '^\s*(Node|Logical)\s*\K.*?(\s|$)' file | perl -lne '$. % 2 ? printf : print' $
    – krock1516
    Apr 11, 2015 at 11:16
2

You should use sed, in my opinion. In the first place, it will usually outperform awk, and, in this case, it offers a more simple solution overall:

sed -n 'N;s/Node \([^ ]*\).*Logical/\1/p' <infile

...which, given your example data, prints...

 WWN:2000000c50f1c8da Path:/dev/rdsk/c1t1d0s2
 WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2

For each line read, sed also gets the Next appended to pattern space following an inserted \newline delimiter. So the above s///ubstitution spans two lines, and prints the two fields you want separated only by a space and only when a match is found.

The above sed syntax should be fully portable to any POSIX system.

1

If you want awk

awk -v RS=' Node ' -v FS=' Logical Path:| ' '/WWN/{print $1,$6}'

Other (may be simple)

awk -F":| " '/Node/{printf "%s ", $3":"$4}/Logical Path/{print $4}'

with remain Path:

awk '/Node/{printf "%s ", $2}/Logical Path/{print $2}'

or

awk '/Node/{wwn=$2}/Logical Path/{print wwn,$2}'

And GNU sed at last:

sed -n '/WWN/{s/^\s*\S* *\|\( \S*\)\{3\}\s*$//g;N;s/\n\s*\S*//;p}'
2
  • its does not work for the situation... $ luxadm probe | awk -v RS=' Node ' -v FS=' Logical Path:| ' '/WWN/{print $1,$6}' awk: syntax error near line 1 awk: bailing out near line 1 you have mail in /var/mail/root
    – krock1516
    Apr 11, 2015 at 10:40
  • @Karn in that case, please edit your question and include the entire output of luxadm probe.
    – terdon
    Apr 11, 2015 at 10:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .