Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am not sure if this possible.

say i have columns like :

Team      Colour      Game      Rainfall      PlayerName  
XYZ       Blue        Cricket   Yes           Kapil

suppose i need to search for any data that is below Game i can do it using awk somthing like :

  awk '{for(i=1;i<NF;i++)
        {
         if($i == "Game")
          {
          GameData=i
          next
          }
        if( i == GameData )
          {
          print "Column below Game is" $i
          }
        }
      }'

but what if i am not sure value in some columns can be missing like any one of

XYZ       Blue     

could be missing or both could be missing or present.

EDIT : Lets say first letter T of team(first column) is always at the begining and first letter C of Colour is always after 10 characters from the begining, first letter G of Game is always after 20 characters from the begining and so on.

share|improve this question
    
As @Joel Davis said: You have to tell us how the fields are seperated. Do they begin at fixed positions, padded with blanks? –  Hauke Laging May 11 '13 at 15:23
    
yes extacly as you can see in the example above left justified.and at the same distance from the begining/origin. –  munish May 11 '13 at 15:28
    
Your code example has several problems: (1) it is not useful to have hardcoded selector variables in the code. (2) The column detection must and may happen in the first line only. (3) After column detection the column can be addressed directly, no comparison necessary. (4) As you use field width you have to strip off the blanks. –  Hauke Laging May 11 '13 at 16:43

3 Answers 3

I don't know that there's really a good way to recover this information, if the fields in the middle are blank and you allow the delimiter to go on an unspecified amount of characters, how could you ever tell that the field you end up seeing is Colour and not PlayerName ?

At some point the data needs to be formatted in a way that can be parsed programmatically and anything else is just the result of poor data feeds. You need to switch to a single character delimiter if you want to be able to leave random fields out.

If it's an issue of readability, you can certainly script a presentation of the data where the fields are padded out with whitespace until they're under the proper columns, but doing so destroys the information that would let you know which field you're actually looking at, so it's a one-way process.

share|improve this answer
1  
Sorry but that is wrong (and I just gave an upvote for the first part...): Of course, padding with whitespace to the right does deliver the information which field this is. awk even has a feature for using just this: FIELDWIDTHS. You cannot pad with tabs and blanks though (or have to convert the tabs first). If the information which field you are looking at were gone then you could not even pad to the right column: How would you know what the right column (or: the right padding) is? It just doesn't work with the the usual awk field separation method. –  Hauke Laging May 11 '13 at 15:21
    
i am not sure about using FIELDWIDTHS in awk but +1 anyway the answer seemed ok to me.Thanks @Joel and Hauke –  munish May 11 '13 at 15:25
    
@HaukeLaging, thanks for the information. For my own education, how would FIELDWIDTHS react to a field that gets padded out to maintain columns after a row value that's longer than the header? –  Joel Davis May 11 '13 at 17:20
    
For example a value of Griffin under lname ? –  Joel Davis May 11 '13 at 17:21
    
The field width must be the length of the longest entry plus one (for the separating space). You have to strip off the blanks from the field value because awk takes all the covered positions (several blanks in this case). Have a look at the code in my answer, that may be helpful. But I learnt from another answer that FIELDWIDTHS is non-standard (GNU once again). –  Hauke Laging May 11 '13 at 18:13
awk -v field="Game" -v FIELDWIDTHS="10 12 10 13 25" '
  NR == 1 {cmpstr="^" field " *$";
    for (i=0;i<6;i++) if ($i ~ cmpstr) { fieldindex=i; next;}; exit 1};
  {gsub(" ","",$fieldindex); if ($fieldindex != "") print $fieldindex;}' inputfile

Edit 1: Exit with error code if not matching column is found.

Edit 2: Don't output empty lines.

share|improve this answer

You could use FIELDWIDTHS, though that is a gawk extension and not as portable. You could also name fields as in e.g.:

awk '
BEGIN {
    FIELDWIDTHS = "10 9 13 11 32"
    team=1; colour=2; game=3; rainfall=4; name=5;
}

NR == 1 {
    next
}
/./ {
    print $3, $name
} ' fixwdata

Widths in FIELDWIDTHS is composed as follows:

  Team      Colour   Game      Rainfall   PlayerName  
  XYZ       Blue     Cricket   Yes        Kapil
# <-  10  -><-  9  -><-  10  -><-  11   -><-     NN      ->  FIELDWIDTHS
#     $1        $2       $3        $4            $5          Field numbers

Optionally you could use e.g. substr(). If first line holds unique names where no repeat, i.e. not Name, TeamName, you could use index().

This looks a bit fragile. If the data is fixed width you could hard-code this, but some programs also spew fixed width – but also align data according to width of data. So you could get:

Output1:

FLD1 FLD2
foo  bar

Output2:

FLD1   FLD2
foobaz bar

This example asumes no repetition of names in other names:

awk '
function get_fld(fld_name)
{
    return substr($0, col[fld_name"s"], col[fld_name"w"]);
}
BEGIN {
    team=1
    colour=2
    game=3
    rainfall=4
    name=5
}
NR == 1 {
    col["1s"]=0
    col["2s"]=index($0, $2)
    col["3s"]=index($0, $3)
    col["4s"]=index($0, $4)
    col["5s"]=index($0, $5)
    col["1w"]=col["2s"] - 1
    col["2w"]=col["3s"] - col["2s"]
    col["3w"]=col["4s"] - col["3s"]
    col["4w"]=col["5s"] - col["4s"]
    col["5w"]=22
    next
}
/./ {
    printf(\
    "%-5s {\n"\
    "%12s: %s\n"\
    "%12s: %s\n"\
    "%12s: %s\n"\
    "%12s: %s\n"\
    "}\n",
    get_fld(name),
    "Team", get_fld(team),
    "Colour", get_fld(colour),
    "Game", get_fld(game),
    "Rainfall", get_fld(rainfall));
} ' fixwdata

Input:

Team      Colour   Game         Rainfall   PlayerName  
ABC       Blue     Cricket      Yes        Kapil
DEF       Red      Cricket                 Konos
DEF       Yellow   Go                      Kripl
DUX       Black
Zon       Purple   Golf         No         Gim
Zon       Purple   Golf         No         Jom

Output:

Kapil {
        Team: ABC       
      Colour: Blue     
        Game: Cricket      
    Rainfall: Yes        
}
Konos {
        Team: DEF       
      Colour: Red      
        Game: Cricket      
    Rainfall:            
}
Kripl {
        Team: DEF       
      Colour: Yellow   
        Game: Go           
    Rainfall:            
}
      {
        Team: DUX       
      Colour: Black
        Game: 
    Rainfall: 
}
Gim   {
        Team: Zon       
      Colour: Purple   
        Game: Golf         
    Rainfall: No         
}
Jom   {
        Team: Zon       
      Colour: Purple   
        Game: Golf         
    Rainfall: No         
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.