manas
manas

Reputation: 471

comparing a line with its following lines

I have a file named file.txt which contains data in the following format:

John
file
Abr
John
Tutu

I can read the file line by line using the following way:

#!/bin/sh
while read fl
do
echo $fl
done < file.txt

But I want to print a line with its following lines

I tried the script:

#!/bin/sh
prev=""
while read fl; do
    prev="$fl"
done < file.txt

But this script does the things with consecutive lines only. please suggest some better solution.

Expected output:

John  file
John Abr
John John
John Tutu

then
file  Abr
file John
file Tutu

then
Abr John
Abr Tutu

then
John Tutu

Upvotes: 2

Views: 118

Answers (4)

Ed Morton
Ed Morton

Reputation: 203532

If the output order doesn't matter then:

$ cat tst.awk
BEGIN { OFS="\t" }
NR > 1 {
    for (i=1; i<NR; i++) {
        print words[i], $0
    }
}
{ words[NR]=$0 }

$ awk -f tst.awk file
John    file
John    Abr
file    Abr
John    John
file    John
Abr     John
John    Tutu
file    Tutu
Abr     Tutu
John    Tutu

or if it does:

$ cat tst.awk
BEGIN { OFS="\t" }
NR > 1 {
    for (i=1; i<NR; i++) {
        print i, NR, words[i], $0
    }
}
{ words[NR]=$0 }

$ awk -f tst.awk file | sort -k1,2n | cut -f3-
John    file
John    Abr
John    John
John    Tutu
file    Abr
file    John
file    Tutu
Abr     John
Abr     Tutu
John    Tutu

Upvotes: 0

Cole Tierney
Cole Tierney

Reputation: 10314

Using a recursive bash function

#!/bin/bash

list_compare() {
    test ${#@} -lt 2 && return  # terminating condition

    local name="$1"
    shift
    for e in "${@}"; do
        echo -n "$name $e"
        test "$name" == "$e" && echo ' <- match' || echo
    done
    echo
    list_compare "$@"  # call again with what's left after shift
}

list_compare $(<file.txt)

Output

John file
John Abr
John John <- match
John Tutu

file Abr
file John
file Tutu

Abr John
Abr Tutu

John Tutu

Upvotes: 0

RavinderSingh13
RavinderSingh13

Reputation: 133518

1st solution: With single pass Input_file please try following awk code.

awk '
{
  arr[FNR]=$0
}
END{
  for(i=1;i<=FNR;i++){
    for(j=(i+1);j<=FNR;j++){
      print arr[i],arr[j]
    }
  }
}
' Input_file

Explanation: Adding detailed explanation for above.

awk '                            ##Starting awk program from here.
{
  arr[FNR]=$0                    ##Creating arr with index of FNR and value of $0.
}
END{                             ##Starting END block of this program from here.
  for(i=1;i<=FNR;i++){           ##Running 1st loop till FNR value.
    for(j=(i+1);j<=FNR;j++){     ##Running 2nd loop till FNR value, with starting value i+1 here.
      print arr[i],arr[j]        ##Printing array with index of i and j here.
    }
  }
}
' Input_file                     ##Mentioning Input_file name here.


2nd solution: With your shown samples, please try following code.

awk '
FNR==NR{
  arr[++count]=$0
  next
}
{
  for(i=(FNR+1);i<=count;i++){
    print $0,arr[i]
  }
}
' Input_file  Input_file

Explanation: Adding detailed explanation for above.

awk '                             ##Starting awk program from here.
FNR==NR{                          ##Checking condition FNR==NR here.
  arr[++count]=$0                 ##Creating array with index of count with increasing value of 1 and its value is current line.
  next                            ##next will skip all further statements from here.
}
{
  for(i=(FNR+1);i<=count;i++){    ##Running loop from next line to count here.
    print $0,arr[i]               ##Printing current line and array element here.
  }
}
' Input_file  Input_file          ##Mentioning Input_file name here.

Upvotes: 2

user14473238
user14473238

Reputation:

awk's empty RS might suit your data:

awk -F '\n' -v RS= '{for (i=1;i<NF;++i) for (j=i+1;j<=NF;++j) print $i,$j}' file

Upvotes: 3

Related Questions