1

I've got a funky file. Each line ends with newline, and every line after the first starts with a comma. Like so:

blah blah blah
,more blah blah blah
,even more blah blah blah

I simply want to swap the comma and the newline:

blah blah blah,
more blah blah blah,
even more blah blah blah

It's just a few thousand lines long, so I was trying to do it in VI. I've tried various combinations, but nothing works. I think this is close, maybe?

%s//\n,/,/\n/g

But I get an error about trailing characters. I'm sure I'm messing up the separators and escape characters, but I can't figure out where I'm going wrong.

EDIT: I'm assuming it ends with \n, not \r. If I do :set list, each line ends with $.

  • Does it have to be in VI or you accept sed? – guillermo chamorro Nov 7 '19 at 19:56
  • 1
    I'm not picky. Sed, awk, vi, whatever. – Andrew Nov 7 '19 at 19:58
  • When you say 'everyline' do you really mean everyline, or would you prefer something that first checks if the subsequent line starts with a , and if so truncate and append to the current line. – BarBar1234 Nov 7 '19 at 20:08
1

I've came up with this with GNU sed:

sed -Ee 's/^[,]*(.*)$/\1,/' -e '$s/,$//' file

Or replacing in file:

sed -i -Ee 's/^[,]*(.*)$/\1,/' -e '$s/,$//' file

Beggining of line with 0 or more occurences of ,

^[,]*

Capture the pattern from there to the end of the line:

(.*)$

Substitute with the captured pattern and add the , at the end:

\1, 

Delete the , in the las line:

-e '$s/,$//'
  • 1
    yeah, that works since they had the commas on every line. You could add $s/,$// to remove the final comma from the very last line (as in the sample). Alternatively without the capture: sed -Ee 's/^,//; $!s/$/,/' – ilkkachu Nov 7 '19 at 20:14
  • That did it, thanks! – Andrew Nov 7 '19 at 20:17
  • @ilkkachu I went for a cigarette and realize about the last line. Answer edited. – guillermo chamorro Nov 7 '19 at 20:45
0

I simply want to swap the comma and the newline

Doing quite literally just that with Perl:

perl -0 -pe 's/\n,/,\n/g' file.txt
0

If you have GNU sed, you can use the -z / --null-data option if the file fits into memory:

sed -z 's/\n,/,\n/g' file
0
perl -0777pe 's/\n,/,\n/g'

-0777

-0[octal/hexadecimal] :: specifies the input record separator ($/) as an octal or hexadecimal number. If there are no digits, the null character is the separator. Other switches may precede or follow the digits. [...]

The special value 00 will cause Perl to slurp files in paragraph mode. Any value 0400 or above will cause Perl to slurp files whole, but by convention the value 0777 is the one normally used for this purpose.

-p :: causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed:

LINE:
    while (<>) {
        ...             # your program goes here
    } continue {
        print or die "-p destination: $!\n";
    }

If a file named by an argument cannot be opened for some reason, Perl warns you about it, and moves on to the next file. Note that the lines are printed automatically. An error occurring during printing is treated as fatal.

-e commandline :: may be used to enter one line of program. If -e is given, Perl will not look for a filename in the argument list. Multiple -e commands may be given to build up a multi-line script. Make sure to use semicolons where you would in a normal program.

The above just transforms standard-in to standard-out. If you're feeling adventurous you can even make it do in-place replace of files passed-in as arguments:

perl -0777pe 's/\n,/,\n/g' -i file1 file1 ...

-i[extension] :: specifies that files processed by the <> construct are to be edited in-place. It does this by renaming the input file, opening the output file by the original name, and selecting that output file as the default for print() statements. The extension, if supplied, is used to modify the name of the old file to make a backup copy, following these rules:

If no extension is supplied, and your system supports it, the original file is kept open without a name while the output is redirected to a new file with the original filename. When perl exits, cleanly or not, the original file is unlinked. [...]

0

With sed - using a N ... P;D loop to maintain a 2-line buffer:

$ sed -e '$!N;s/\n,/,\n/' -e 'P;D' file
blah blah blah,
more blah blah blah,
even more blah blah blah
0

Of course, the fastest and more to the point solution is:

tr '\n,' ',\n'  < file

That's assuming that there are no other , (as in your sample).

If that is a problem, then use (GNU) sed:

sed -z 's/\n,/,\n/g' file

If the size of the file is a concern (won't fit in memory) use Perl.

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.