2

I am trying to parse data from a log file.

Here is the datafile in:

Data1
Data2
Data3
Data4

My code is as follow:

data=$(cat datafile)
echo "$data" | while read line; read line1;
do
    echo "$line and $line1"
done

My desired output is:

Data1 and Data2
Data2 and Data3
Data3 and Data4

But instead I get:

Data1 and Data2
Data3 and Data4

I do understand why I get this behavior, however I am short on ideas about how to do as I want. Does anybody happen to know a trick?

Thanks

4 Answers4

4

Don't use shell while read loops to process text. Here it's easiest with awk:

awk 'NR > 1 {print prev, "and", $0}; {prev = $0}' < datafile

Or with sed:

sed 'x; 1d; G; s/\n/ and /' < datafile
  • Thanks for your answer. I'm currently reading all of your good practices answers in others posts. You could write a book named "you are using bash wrong" :) – elfamosomojito Jan 30 '20 at 08:07
2

How far would

{ read line
  while read line1
  do
     echo $line and $line1
     line=$line1
  done
 } < datafile

Data1 and Data2 Data2 and Data3 Data3 and Data4

get you?

RudiC
  • 8,969
  • Bingo. Are the brackets the key to this? By the way it works for me now, but I'm considering investigating Stephane Chazelas answer furthermore, it seems to be the best practice one. – elfamosomojito Jan 30 '20 at 08:10
  • The braces enclose a "compund command" which in turn makes sure both leading read and while loop use the same , redirected input. Without them, the while loop would reopen it at line 1. I didn't use awk as I thought you need to perform other shell tasks on each data pair. – RudiC Jan 30 '20 at 08:59
1

One more while read loop...

while read -r line; do 
  printf '%s and %s\n' "$line" "$line"
done < data

Or

while read -r line <&3; do 
  read -r line1
  printf '%s and %s\n' "$line" "$line1"
done 3< data < data

or bash4+ mapfile

mapfile -t array < data

for i in "${!array[@]}"; do 
  printf '%s and %s\n' "${array[$i]}" "${array[$i]}"
done
Jetchisel
  • 1,264
1

I would simply paste the file to its clone with the first line removed:

$ tail -n+2 datafile | paste datafile -
user9101329
  • 1,004