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
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
  • I just updated question . – thinh luu Dec 18 '18 at 7:38
  • @thinhluu I still can't see what's wrong. Sorry. Is it that the Last Name should be removed? – Kusalananda Dec 18 '18 at 7:38
  • I added variable Last Name but i wanna print do not take Last Name . – thinh luu Dec 18 '18 at 7:51
  • @thinhluu This is what my latest modifications to the answer does. – Kusalananda Dec 18 '18 at 7:59
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
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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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