0

I have files like

aaa

bbb

ccc

I need them to sed into aaa\r\nbbb\r\nccc

It should work either for unix and windows replacing them with \r or \r\n accordingly

The problem is that sed adds \n at the end of line but keeps lines separated. How can I fix it?

999
  • 1
  • 1
  • 1
  • 1

4 Answers4

2

These two commands together should do what you want:

sed ':a;N;$!ba;s/\r/\\r/g'
sed ':a;N;$!ba;s/\n/\\n/g'

Pass your input file through both to get the output you want. Theres probably a way to combine them into a single expression.

Stolen and Modified from this question:

How can I replace a newline (\n) using sed?

Community
  • 1
  • 1
bdk
  • 4,769
  • 29
  • 33
  • 1
    Oh, that's cute. You can put it together just by tacking one of the `s` commands on the end of the other program, like so: `sed ':a;N;$!ba;s/\n/\\n/g;s/\r/\\r/g'` I tried to come up with that `:a;N;$!ba` sequence but couldn't get it right. – zwol Mar 24 '11 at 16:31
  • Thank you but I still get multiple lines. I run it on mac os x. – 999 Mar 24 '11 at 16:33
  • ... why'd you tag it "linux" if you're on OSX? – zwol Mar 24 '11 at 17:42
1

It's possible to merge lines in sed, but personally, I consider needing to change line breaks a sign that it's time to give up on sed and use a more powerful language instead. What you want is one line of perl:

perl -e 'undef $/; while (<>) { s/\n/\\n/g; s/\r/\\r/g; print $_, "\n" }'

or 12 lines of python:

#! /usr/bin/python
import fileinput
from sys import stdout
first = True
for line in fileinput.input(mode="rb"):
    if fileinput.isfirstline() and not first:
        stdout.write("\n")
    if line.endswith("\r\n"): stdout.write(line[:-2] + "\\r\\n")
    elif line.endswith("\n"): stdout.write(line[:-1] + "\\n")
    elif line.endswith("\r"): stdout.write(line[:-1] + "\\r")
    first = False
if not first: stdout.write("\n")

or 10 lines of C to do the job, but then a whole bunch more because you have to process argv yourself:

#include <stdio.h>

void process_one(FILE *fp)
{
    int c;
    while ((c = getc(fp)) != EOF)
        if (c == '\n') fputs("\\n", stdout);
        else if (c == '\r') fputs("\\r", stdout);
        else putchar(c);
    fclose(fp);
    putchar('\n');
}

int main(int argc, char **argv)
{
    FILE *cur;
    int i, consumed_stdin = 0, rv = 0;
    if (argc == 1) /* no arguments */
    {
        process_one(stdin);
        return 0;
    }

    for (i = 1; i < argc; i++)
    {
        if (argc[i][0] == '-' && argc[i][1] == 0)
        {
            if (consumed_stdin)
            {
                fputs("cannot read stdin twice\n", stderr);
                rv = 1;
                continue;
            }
            cur = stdin;
            consumed_stdin = 1;
        }
        else
        {
            cur = fopen(ac[i], "rb");
            if (!cur)
            {
                perror(ac[i]);
                rv = 1;
                continue;
            }
        }
        process_one(cur);
     }
     return rv;
 }
zwol
  • 135,547
  • 38
  • 252
  • 361
  • 1
    Thanks but can I do it without perl? – 999 Mar 24 '11 at 16:38
  • If bdk's suggestion doesn't work for you, I'm not aware of any better way than using perl. (Or C. This would be about 20 lines of C.) OSX comes with perl, so I don't see what the problem is? – zwol Mar 24 '11 at 17:43
1
tr -s '\r' '\n' <file | unix2dos

EDIT (it's been pointed out that the above misses the point entirely! •///•)

tr -s '\r' '\n' <file | perl -pe 's/\s+$/\\r\\n/'

The tr gets rid of empty lines and dos line endings. The pipe means two processes—good on modern hardware.

bobbogo
  • 14,989
  • 3
  • 48
  • 57
  • That doesn't do what the OP asked for. – zwol Mar 24 '11 at 18:04
  • See my and bdk's answers. The OP wants to convert LF and CR characters to C-style *escape sequences*, ending up with a file with no line breaks in it at all. – zwol Mar 24 '11 at 19:10
  • @Zack: Doh! I _must learn to read the questions. I'll add the ncessary. TVM. – bobbogo Mar 25 '11 at 10:40
1

awk '{printf("%s\\r\\n",$0)} END {print ""}' file

glenn jackman
  • 238,783
  • 38
  • 220
  • 352