Yes I know there are a number of questions (e.g. (0) or (1)) which seem to ask the same, but AFAICS none really answers what I want.
What I want is, to replace any occurrence of a newline (LF) with the string \n, with no implicitly assumed newlines... and this with POSIX only utilities (and no GNU extensions or Bashisms) and input read from stdin with no buffering of that is desired.
So for example:
printf 'foo' | magicshould givefooprintf 'foo\n' | magicshould givefoo\nprintf 'foo\n\n' | magicshould givefoo\n\n
The usually given answers, don't do this, e.g.:
- awk
printf 'foo' | awk 1 ORS='\\ngivesfoo\n, whereas it should give justfoo
so adds an\nwhen there was no newline. - sed
would work for justfoobut in all other cases, like:
printf 'foo\n' | sed ':a;N;$!ba;s/\n/\\n/g'givesfoo, whereas it should givefoo\n
misses one final newline.
Since I do not want any sort of buffering, I cannot just look whether the input ended in an newline and then add the missing one manually.
And anyway... it would use GNU extensions.
sed -z 's/\n/\\n/g'
does work (even retains the NULs correctly), but again, GNU extension. - tr
can only replace with one character, whereas I need two.
The only working solution I'd have so far is with perl:
perl -p -e 's/\n/\\n/'
which works just as desired in all cases, but as I've said, I'd like to have a solution for environments where just the basic POSIX utilities are there (so no Perl or using any GNU extensions).
Thanks in advance.
CodePudding user response:
Here is a tr sed solution that should work on any POSIX shell as it doesn't call any gnu utility:
printf 'foo' | tr '\n' '\7' | sed 's/\x7/\\n/g'
foo
printf 'foo\n' | tr '\n' '\7' | sed 's/\x7/\\n/g'
foo\n
printf 'foo\n\n' | tr '\n' '\7' | sed 's/\x7/\\n/g'
foo\n\n
Details:
trcommand replaces each line break with\x07sedcommand replace each\x07with\\n
CodePudding user response:
One way would be to use Awk to modify the default value of input RS to some random character, so that the \n character (otherwise default value RS) is available for replacement with literal \\n
printf 'foo' | awk '{ gsub("\n", "\\n") }1' RS="#"
foo
printf 'foo\n' | awk '{ gsub("\n", "\\n") }1' RS="#"
foo\n
printf 'foo\n\n' | awk '{ gsub("\n", "\\n") }1' RS="#"
foo\n\n
