Anand
Anand

Reputation: 1

Use of awk/sed to get specific data in rows based on a pattern and arrange them in columns in unix

I have a file as below:

ID: 1  
Name: Admin1  
Class: Administrator  
Class: Leader  
AliasName: User1  
AliasedObject: Administrator,Admin1  

ID: 2  
Name: Admin2  
Class: Administrator  
Class: Leader  
AliasName: User2  
AliasedObject: Administrator,Admin2  

ID: 3  
Name: Admin3  
Class: Administrator  
Class: Leader  
AliasName: User3  
AliasedObject: Administrator,Admin3  

Now I have to filter only the AliasName and AliasedObject as below:

AliasName  AliasedObject  
User1      Administrator,Admin1  
User2      Administrator,Admin2  
User3      Administrator,Admin3  

How can I do this in Unix using the AWK/SED commands?

Upvotes: 0

Views: 87

Answers (4)

JJoao
JJoao

Reputation: 5337

#!/usr/bin/perl -ln

BEGIN{ $/='';  print "AliasName\tAliasedObject";}

%F = m/(?:^|\n)(\S+):\s*(.*)/g;
print "$F{AliasName}   $F{AliasedObject}"

This way, some of the fields can be empty, absent or written in a different order.

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203169

Whenever you have data that includes name=value pairs, it's a good idea to create a name2value array and access the fields by their names, e.g.:

$ cat tst.awk
BEGIN {
    RS=""; FS="\n"; OFS="\t"
    numNames = split("AliasName AliasedObject",names,/ /)
    for (i=1; i<=numNames; i++) {
        printf "%s%s", names[i], (i<numNames?OFS:ORS)
    }
}
{
    delete n2v
    for (i=1;i<=NF;i++) {
        name  = gensub(/:.*/,"","",$i)
        value = gensub(/[^:]+:\s*/,"","",$i)
        n2v[name] = value
    }
    for (i=1; i<=numNames; i++) {
        printf "%s%s", n2v[names[i]], (i<numNames?OFS:ORS)
    }
}
$ awk -f tst.awk file
AliasName       AliasedObject
User1   Administrator,Admin1
User2   Administrator,Admin2
User3   Administrator,Admin3

That way if you want to add additional fields to be printed later you just change split("AliasName AliasedObject",names,/ /) to split("AliasName AliasedObject Class",names,/ /) or whatever (but having 2 different fields both named "Class" in your data would be an issue you should fix at source if that really exists in your data).

The above uses GNU awk for a couple of extensions (delete array, gensub(), and \s), but is easily tweaked to work for any awk if necessary.

While the above is the best approach in general, for this particular case if your input file values contain no blanks, I'd just use @fedorqui's concise solution: https://stackoverflow.com/a/29698956/1745001.

Upvotes: 4

fedorqui
fedorqui

Reputation: 289495

Supposing the file is exactly like this, you can set the record separator to the paragraph (that is, RS="", thanks Ed Morton) and then get the blocks with some data:

awk 'BEGIN{RS=""; print "AliasName","AliasedObject"}
     {print $10, $12}' file

Test

$ awk 'BEGIN{RS=""; print "AliasName","AliasedObject"} {print $10,$12}' a
AliasName AliasedObject
User1 Administrator,Admin1
User2 Administrator,Admin2
User3 Administrator,Admin3

Upvotes: 3

NeronLeVelu
NeronLeVelu

Reputation: 10039

sed -n '1 i\
AliasName AliasedObject
/^AliasName/ { 
   s/.*:[[:space:]]*//
   N
   s/.AliasedObject:[[:space:]]*/    /p
   }' YourFile
  • assume file with same record structure
  • load expecte field line, reformat and add the next one. Print only if second pattern modification occur (little security)

Upvotes: 2

Related Questions