1

I have a file with data as follows:

STUDENT DETAILS
NAME MARKS STD
XYZ 20 I
RANK SCHOOL TEACHER GRADE
5 TTT ANON B
POSITION
5
STUDENT DETAILS
NAME MARKS STD
ABC              40                I
RANK SCHOOL TEACHER GRADE
5 TTT ANON A
POSITION
5

I want my output as:

NAME MARKS STD RANK SCHOOL TEACHER GRADE POSITION
XYZ  20     I   5    TTT   ANON    B     5
ABC  40     I   5    TTT   ANON    A     5

I have tried finding the pattern STUDENT DETAILS through awk and printing 2nd, 5th and 8th lines after that. But the line needs to be concatenated.

I ran:

awk '/STUDENT DETAILS/{nr[NR];nr[NR+2]; nr[NR+5]; nr[NR+8]}; END {for (i in nr) print nr[i]}' file.txt > filenew.txt

How can I achieve this?

  • How is the fields delimited in the input? By tabs? – Kusalananda Jun 20 '19 at 12:27
  • Yes,it is delimited by tabs – Isha Jun 20 '19 at 12:29
1
awk '
    BEGIN { OFS="\t"; maxLines=7 }
    { lineNr=(NR-1) % maxLines + 1; $1=$1; lines[lineNr]=$0 }
    NR == maxLines     { print lines[2], lines[4], lines[6] }
    lineNr == maxLines { print lines[3], lines[5], lines[7] }
' file
NAME    MARKS   STD     RANK    SCHOOL  TEACHER GRADE   POSITION
XYZ     20      I       5       TTT     ANON    B       5
ABC     40      I       5       TTT     ANON    A       5
0

you can't read ahead in awk, you have to remember pattern

awk file (u.awk below)

/STUDENT/ { li=NR;}
NR == li+2 { mark[li]=$0 }
NR == li+4 { pos[li]=$0 }
END { for (m in mark) printf "%s %s\n",mark[m],pos[m] ;}

where

  • /STUDENT/ { li=NR;} remember line where record start
  • NR == li+2 { mark[li]=$0 } when current line is +2, remember mark (likewise for position)

when run with you sample data (I delete empty lines, adjust +2/+4 if present on actual file), this give

awk -f u.awk liste-1.txt

XYZ 20 I 5 TTT ANON B
ABC              40                I 5 TTT ANON A

generation of header omited.

0

If you pre-split the data into records, you can get away with printing the relevant fields:

# Pre-splitting
sed '/^STUDENT/ { 1!s/^/\n/; }' infile |

# Reorder the record:
awk -v RS= -v FS='\n' '
  NR == 1 { print $2, $4, $6 }
          { print $3, $5, $7 }'        |

# Pretty-print columns
column -t

Output:

NAME  MARKS  STD  RANK  SCHOOL  TEACHER  GRADE  POSITION
XYZ   20     I    5     TTT     ANON     B      5
ABC   40     I    5     TTT     ANON     A      5
0

Gnu sed constructs and extended regex mode enabled:

 $ sed -nEe '
      1,6{
         N;7!s/^/\n/;7!D;h





  s/(.*)\n(.*)\n(.*)\n(.*)\n(.*)\n(.*)\n(.*)/\2\t\4\t\6/p
         ba
     }
    /STUDENT/!{H;$!d;:a;g;}

      s/(.*)\n(.*)\n(.*)\n(.*)\n(.*)\n(.*)\n(.*)/\3\t\5\t\7/p
 ' file.txt


 NAME   MARKS   STD RANK    SCHOOL  TEACHER GRADE   POSITION
 XYZ    20  I   5   TTT ANON    B   5
 ABC    40  I   5   TTT ANON    A   5
0
Tested with below script and it worked fine


STEP1:

header=`sed '/STUDENT/d' r.txt |sed -n '1~2p'| sort | uniq| sed "N;s/\n/ /g"| sed "N;s/\n/ /g"`

count=`sed '/STUDENT/d'  o.txt|wc -l`
sed -i '/STUDENT/d' o.txt

STEP2:
for ((i=1;i<=$count;i++)); do j=$(($i+5)); sed -n ""$i","$j"p" o.txt| sed -n '2~2p'|sed -r "s/\s+/ /g"|sed "N;s/\n/ /g"|sed "N;s/\n/ /g"; i=$j; done| awk -v header="$header" 'BEGIN{print header}{print $0}'| sed "s/ /\t/g"

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.