awk to get value for a column of next line and add it to the current line in shellscript

Viewed 141

I have a csv file lets say lines

cat lines
1:abc
6:def
17:ghi
21:tyu

I wanted to achieve something like this

1:6:abc
6:17:def
17:21:ghi
21::tyu

Tried the below code by didn't work

awk 'BEGIN{FS=OFS=":"}NR>1{nln=$1;cl=$2}NR>0{print $1,nln,$2}' lines
1::abc
6:6:def
17:17:ghi
21:21:tyu

Can you please help ?

3 Answers

1st solution: Here is a tac + awk + tac solution. Written and tested with shown samples only.

tac Input_file | 
awk '
BEGIN{
  FS=OFS=":"
}
{
  prev=(prev?$2=prev OFS $2:$2=OFS $2)
}
{
  prev=$1
}
1
' | tac

Explanation: Adding detailed explanation for above code.

tac Input_file |     ##Printing lines from bottom to top of Input_file.
awk '                ##Getting input from previous command as input to awk.
BEGIN{               ##Starting BEGIN section from here.
  FS=OFS=":"         ##Setting FS and OFS as colon here.
}
{
  prev=(prev?$2=prev OFS $2:$2=OFS $2)  ##Creating prev if previous NOT NULL then add its value prior to $2 with prev OFS else add OFS $2 in it.
}
{
  prev=$1            ##Setting prev to $1 value here.
}
1                    ##printing current line here.
' | tac              ##Sending awk output to tac to make it in actual sequence.


2nd solution: Adding Only awk solution with 2 times passing Input_file to it.

awk '
BEGIN{
  FS=OFS=":"
}
FNR==NR{
  if(FNR>1){
    arr[FNR-1]=$1
  }
  next
}
{
  $2=(FNR in arr)?(arr[FNR] OFS $2):OFS $2
}
1
'  Input_file  Input_file

Here is a potential AWK solution:

cat lines
1:abc
6:def
17:ghi
21:tyu

awk -F":" '{num[NR]=$1; letters[NR]=$2}; END{for(i=1;i<=NR;i++) print num[i] ":" num[i + 1] ":" letters[i]}' lines
1:6:abc
6:17:def
17:21:ghi
21::tyu

Formatted:

awk '
BEGIN {FS=OFS=":"}
{
  num[NR] = $1;
  letters[NR] = $2
}
END {for (i = 1; i <= NR; i++)
        print num[i], num[i + 1], letters[i]
}
' lines
1:6:abc
6:17:def
17:21:ghi
21::tyu

Basically this is your solution but I switched the order of the code blocks and added the END block to output the last record, you were close:

awk 'BEGIN{FS=OFS=":"}FNR>1{print p,$1,q}{p=$1;q=$2}END{print p,"",q}' file

Explained:

$ awk 'BEGIN {
    FS=OFS=":"    # delims
}
FNR>1 {           # all but the first record 
    print p,$1,q  # output $1 and $2 from the previous round
}
{
    p=$1          # store for the next round
    q=$2
}
END {             # gotta output the last record in the END
    print p,"",q  # "" feels like cheating
}' file

Output:

1:6:abc
6:17:def
17:21:ghi
21::tyu
Related