1

I have a text file which contains data in the below format.

1|0|this is test file line1
2|1|this is test file line2
3|1|this
is
test
file line4

Any line that does not contain | should be appended to the previous line which contains |

Output:

1|0|this is test file line1
2|1|this is test file line2
3|1|this is test file line4
1
  • 11
    Ok, but we're not a script-writing service
    – janos
    Dec 17, 2017 at 15:58

6 Answers 6

4

One way is to use Awk to implement the following algorithm:

  • Track the previous line in prev
  • If the line contains |, and it's not the first line, then print prev. After that, store the current line in prev
  • If the line doesn't contain |, then append it to prev
  • At the end of the script, print prev

For example like this:

awk '/\|/ { if (NR > 1) print prev; prev=$0 }
     !/\|/ { prev = prev $0 }
     END { print prev }' input
0
2

Use | as the field separator: if the line contains a | then the NF variable will be greater than one.

awk -F'|' 'NR > 1 && NF > 1 {print ""} {printf "%s", $0} END {print ""}' file
1
  • That's close but does not give the required result. Dec 17, 2017 at 16:16
2
awk '/\|/ { if (printed==1) print ""; else printed=1;
    printf "%s",$0; next; }; { printf " %s",$0 }; END { print ""; }' inputfile

Or, if you don't care about the leading newline, shorter:

awk '/\|/ { printf "\n%s",$0; next; }; { printf " %s",$0 }; END { print ""; }' inputfile
1

Awk is my go-to utility for text manipulation:

awk '/\|/ && NR>1 { printf "\n" } !/\|/ && NR>1 { printf " " } { printf $0 } END { printf "\n" }' file
  1. Print a newline character if the line contains | (but not for the first line):
    /\|/ && NR>1 { printf "\n" }
  2. Otherwise, print a space (but not for the first line):
    !/\|/ && NR>1 { printf " " }
  3. Print the entire line, without a trailing newline character:
    { printf $0 }
  4. Print a newline at the end of the file:
    END { printf "\n" }
0

One more awk:

awk -F'|' 'NR>1{printf prev (NF>1?"\n":" ")}{prev=$0}END{print prev}' file

Testing

$ cat file1
1|1|this is test file line1
2|2|this is test file line2
3|3|this
is
test
file line3
4|4|this is test file line4
5|5|this is
test file
line5
6|6|this is test file line6

$ awk -F'|' 'NR>1{printf prev (NF>1?"\n":" ")}{prev=$0}END{print prev}' file1
1|1|this is test file line1
2|2|this is test file line2
3|3|this is test file line3
4|4|this is test file line4
5|5|this is test file line5
6|6|this is test file line6 
0

I would do this using Perl:

perl -e '$f=1;while(<>){chomp;print(($f?"":/\|/?"\n":" ").$_);$f=0}'

Alternatively, you can use this sed script:

sed -E ':s;N;s/\n([^\n|]*)$/ \1/;bs'

It is a loop that

  • N reads a line and appends it to the pattern space
  • s/\n([^\n|]*)$/ \1/ if the line in the pattern space does not contain |, replace the newline with a space
  • bs jump back to the :s label

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .