echo a file as a single line with \n's

5,029

Solution 1

The solution I used was.

< file.txt sed '$!G' | paste -sd '\\n' -
  • sed '$!G' appends an empty line to each line of input except the last ($) one.
  • paste -sd '\\n' pastes those resulting lines alternatively with backslash and n. And adds a newline in the end to result in valid text output.

Solution 2

Using the Perl sledgehammer:

$ perl -pe 's/\n/\\n/' < file.txt ; echo

The echo is there to print a trailing newline just in case it's wanted for display purposes. This changes the NL on the last line to \n too.

Or a rather straightforward solution in just Bash, assuming the file doesn't contain any embedded NUL bytes. Though note that this loads the whole file in memory:

$ IFS= read -r -d '' text < file.txt; printf '%s\n' "${text//$'\n'/\\n}"

Solution 3

Beware of a few special cases you may need to consider here. Let's take as example 4 files:

  • file1 an empty file
  • file2 a file with a single newline (␤) character (one empty line)
  • file3 a proper text file like:

    foo␤
    bar␤
    
  • file4 a file with the last line non-delimited:

    foo␤
    bar
    

If you want:

  • file1: empty
  • file2: \n␤
  • file3: foo\nbar\n␤
  • file4: foo\nbar␤

(for instance so that you can reconstruct the file by passing the output to printf %b).

Then, you could do:

perl -pe 's/\n/\\n/; END{print "\n" if $.}' < file

Or with GNU awk:

gawk '{printf "%s", $0 (RT ? "\\n" : "")}
      END{if (NR) print ""}' < file

You can adapt if you want to ignore the delimiter of the last line if any, or don't want the trailing newline, but then you may want to test on those 4 different cases that it does what you want as you'll probably find that you need to have special treatments for some of them.

For instance, your

< file sed '$!G' | paste -sd '\\n' -

solution to ignore the delimiter of the last line produces one empty line for both file1 and file2 (and for not-properly-delimited text (file4) may not work properly with all sed/paste implementations as those are meant to deal with valid text).

perl -pe 's/\n?$/eof ? "\n" : "\\n"/e' < file

may be more portable, and maybe slightly better for file1 and file2 which it would leave untouched.

Solution 4

tr alone can't do it since you need to replace one character by two characters. sed alone can't do it easily since it outputs a newline at the end of everything it prints. But you can do it by combining the two: add \n at the end of every line, then remove the line breaks.

sed 's/$/\\n/' | tr -d '\n'

This produces a file that ends with \n and no line break. If you want a newline at the very end, echo it:

{ sed 's/$/\\n/' | tr -d '\n'; echo; }

(Note that this turns an empty file into a file with a single empty line.) If you don't want the last \n, sed it away:

sed 's/$/\\n/' | tr -d '\n' | sed 's/\\n$//'
Share:
5,029

Related videos on Youtube

Louise McMahon
Author by

Louise McMahon

Updated on September 18, 2022

Comments

  • Louise McMahon
    Louise McMahon almost 2 years

    I have a multi line text file that I want to echo out as a single line file where the new lines are shown as \n.

    Any pointers would be great.

    • Sundeep
      Sundeep almost 7 years
      something like this? seq 5 | awk -v ORS='\\n' '1'
  • Sundeep
    Sundeep almost 7 years
    you can avoid the echo using perl -pe 's/\n/\\n/; END{print "\n"}' or if last \n is not needed, perl -pe 's/\n/\\n/ if !eof'
  • Louise McMahon
    Louise McMahon almost 7 years
    I ended up using the solution in your original comment ` cat file.txt | sed '$!G' | paste -sd '\\n'`
  • Stéphane Chazelas
    Stéphane Chazelas almost 7 years
    @Louise, OK, though see edit.
  • ilkkachu
    ilkkachu almost 7 years
    @Sundeep, I know, but that's longer and uglier. :D I'm not sure what to think about the last line.