0

I have the following text:

Name= Garen
Class= 9C
School= US
Name= Lulu
Class= 4A
Name= Kata
Class= 10D
School= UK

I got the awk cmd below:

awk '$Name ~/Name/ {printf $0;} $Class ~/Class/ {printf $0;} $School ~/School/ {print $0;} ' file.txt

But it outputs in a new line. Like this:

Name= Garen Class= 9C School= US
Name= Lulu Class= 4A Name= Kata Class= 10D School= UK

I want it to output like this :

Name= Garen ,Class= 9C ,School= US
Name= Lulu , Class= 4A ,
Name= Kata ,Class= 10D ,School= UK

if it falls into a situation :

Name= Garen
Class= 9C
Last Name= Wilson 
School= US

Name= Lulu
Class= 4A
Last Name= Miller

Name= Kata
Class= 10D
School= UK
Last Name= Thomas

and print:

Name= Garen,Class= 9C,School= US

Name= Lulu,Class= 4A

Name= Kata,Class= 10D,School= UK
Ryan
  • 3

3 Answers3

0
awk '$Name ~/Name/ {printf $0;} $Class ~/Class/ {printf $0;} $School ~/School/ {print $0;} ' file.txt

All of $Name, $Class and $School will act exactly as $0, because the Name, Class and School variables are not defined and in awk any undefined variable has the numeric value of 0 and (at least with mawk and gawk) the $ operator will simply convert its argument to a number. Other awk implementations may bail out with an error (the behavior is unspecified by the standard).

Try this instead:

awk -F ' *= *' '$1~/^(Name|Class|School)$/{
       if($1 in a){ for(i in a) delete a[i]; comma = ""; printf ORS }
       printf "%s%s= %s", comma, $1, $2; a[$1] = comma = ", "
     }
     END{if(comma) printf ORS}
' file.txt

Name= Garen, Class= 9C, School= US
Name= Lulu, Class= 4A
Name= Kata, Class= 10D, School= UK

The example above tries hard to group key/value tuples no matter what order they're in, and be general (it will work the same on the 1st sample input if the $1~/.../ pattern is removed); but if you know that Name is always first and always present, then everything is much easier:

awk '/^Name=/{printf "%s%s", nl, $0; nl=ORS}
     /^(Class|School)=/{printf ", %s", $0}
     END{if(nl) printf ORS}' /tmp/file.txt
0
$ awk -v OFS=',' '/^Name/ { if (line != "") print line; line = $0; next } { line = line OFS $0 } END { if (line != "") print line }' file
Name= Garen,Class= 9C,School= US
Name= Lulu,Class= 4A
Name= Kata,Class= 10D,School= UK

With the updated input in the question, this produces

Name= Garen,Class= 9C,Last Name= Wilson ,School= US,
Name= Lulu,Class= 4A,Last Name= Miller,
Name= Kata,Class= 10D,School= UK,Last Name= Thomas

If you want to delete the Last Name bit, ignore it explicitly in the awk code:

$ awk -v OFS=',' '/^Last Name/ { next } /^Name/ { if (line != "") print line; line = $0; next } { line = line OFS $0 } END { if (line != "") print line }' file
Name= Garen,Class= 9C,School= US,
Name= Lulu,Class= 4A,
Name= Kata,Class= 10D,School= UK

The awk code, as a freestanding awk program with comments:

BEGIN {
    # Set output field separator to a comma.
    # This can also be done with -v OFS="," on the command line.

    OFS = ","
}

/^Last Name/ {
    # Ignore these lines
    next
}

/^Name/ {
    # A line starts with "Name".
    # Print the accumulated line and reset the line variable.
    # Continue immediately with next line of input.

    if (line != "")
        print line

    line = $0
    next
}

{
    # Accumulate lines in the line variable.
    # Delimit each input data with OFS (a comma).

    line = line OFS $0
}

END {
    # Print the last accumulated line.

    if (line != "")
        print line
}

With sed (this is an almost identical solution from an answer to another question)

/^Last Name/ d;             # ignore these lines
/^Name/ b print_previous;   # print previous record
H;                          # append this line to hold space
$       b print_previous;   # print previous (last) record
d;                          # end processing this line

:print_previous;            # prints a record accumulated in the hold space
x;                          # swap in the hold space
/^$/ d;                     # if line is empty, delete it
s/\n/,/g;                   # replace embedded newlines by commas
                            # (implicit print)

Running it:

$ sed -f script.sed file
Name= Garen,Class= 9C,School= US
Name= Lulu,Class= 4A
Name= Kata,Class= 10D,School= UK
Kusalananda
  • 333,661
0

You can use awk for this, with the following one-liner, as follow:

awk -F\< '/Name=/ {LGT=length($2);printf("\n%s,",substr($2,6,LGT))};
/Class=/ {LGT=length($2);printf(" %s,",substr($2,6,LGT))}; 
/School=/ {LGT=length($2);printf(" %s",substr($2,6,LGT))};
END {printf("\n") }' file.txt

This solution will print records (i.e. lines in your original file.txt file) in the order in which they appear in file.txt. I added it because it is a (simple) example of how to parse and manipulate strings with awk.

As in previous answers, file.txt contains:

<text>Name= Garen</text>
<text>Class= 9C</text>
<text>School= US</text>
<text>Name= Lulu</text>
<text>Class= 4A</text>
<text>Name= Kata</text>
<text>Class= 10D</text>
<text>School= UK</text>

Output is:

Name= Garen, Class= 9C, School= US
Name= Lulu, Class= 4A
Name= Kata, Class= 10D, School= UK
Cbhihe
  • 2,701