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
  • 10
    Ok, but we're not a script-writing service – janos Dec 17 '17 at 15:58
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
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
  • That's close but does not give the required result. – Hauke Laging Dec 17 '17 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

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.