I'd use perl for this, not sed - because perl's support for multi-line strings makes it easy:
$ perl -0777 -n -e 's/\n//g; s/"p1"/\n$&/g; s/^\n//; print "$_\n"' input.txt
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data
- -0777 tells perl to read the entire file into memory at once (i.e. "slurps" it into variable
$_
)
- -n makes perl run similarly to
sed -n
(i.e. read the input without auto-printing anything)
The script first deletes all newline characters, then adds a new line before every "p1"
, then deletes the newline that probably adds to the beginning of the string (assuming the first line begins with "p1"
).
Finally, the modified input is printed with a trailing newline (so that the output is valid for a text file - unix text files must end in a newline. Many tools work just fine with almost-text-files that don't end with a newline but a) some don't - they can't process the last "line" because it doesn't end with a newline, according to POSIX that technically isn't a "line", b) while it's good to be flexible in what you accept as input, it's even better to produce correct output, c) not printing the final newline looks ugly and causes the next shell prompt to appear on the same line as the output, and d) similarly it causes problems when cat
-ing multiple files or appending text to a file. See What's the point in adding a new line to the end of a file?)
Alternatively:
$ perl -0777 -n -e 's/\n//g; s/(.)("p1")/$1\n$2/g; print "$_\n"' input.txt
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data
Like the first version, this deletes all newline characters, but then it adds a newline before every instance of "p1"
that follows another character (.
) - i.e. not the first line. Then it prints the modified input with a trailing newline.
Yet another variant:
$ perl -0777 -p -e 's/\n//g; s/(.)("p1")/$1\n$2/g; s/$/\n/' input.txt
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data
This uses perl's -p
option instead of -n
. -p
makes perl run like sed (i.e. read the input and automatically print it after any modifications). Otherwise, it's very similar to the second version above but uses s/$/\n/
to add a newline to the end of the input before it is auto-printed.
data
contain? Can it, for example, contain the string"p1"
or embedded newlines?