57

I want add a comma at the end of every line of this kind of file except the last line:

I have this now:

{...}
{...}
{...}
{...}

I want this:

{...},
{...},
{...},
{...}

How can I do it with the command line? Is it possible with sed command?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Joan Triay
  • 1,518
  • 6
  • 20
  • 35

3 Answers3

122

The following sed script has an address expression $! which matches lines which are not the last, and a substituton action s/$/,/ which adds a comma next to the end of line.

sed '$!s/$/,/' file

(The $ in the address refers to the last line while the $ in the regular expression in the substitution refers to the last character position on every line. They are unrelated, though in some sense similar.)

This prints the modified contents of file to standard output; redirect to a different file to save them to a file, or use sed -i if your sed supports that. (Some variants require an empty argument to the -i option, notably *BSD / OSX sed.)

If your task is to generate valid JSON from something which is not, I'm skeptical of this approach. Structured formats should be manipulated with tools which understand structured formats, not basic line-oriented tools; but if this helps you transform line-oriented data towards proper JSON, that's probably a valid use.

... As an afterthought, maybe you want to wrap the output in a set of square brackets, too. Then it's actually technically valid JSON (assuming each line is a valid JSON fragment on its own).

sed '1s/^/[/;$!s/$/,/;$s/$/]/' file

On the first line (address expression 1) substitute in an opening square bracket at beginning of line (s/^/[/). On lines which are not the last, add a trailing comma, as above. On the line which is the last (address expression $) add a closing square bracket at the end of line (s/$/]/). If you prefer newlines to semicolons, that's fine; many sed dialects also allow you to split this into multiple -e arguments.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • I want with -i but not works, is this the correct command? `sed -i '$!s/$/,/' file` – Joan Triay Jan 26 '16 at 19:17
  • Awesome! I made a little script with this trick to export a JSON line file to a JSON file, calling it like this `./jl2json.sh sample.jsonl sample.json`. Take a look here https://gist.github.com/mrsarm/24e8531ef8375c768e03d1c1aea67262 – Mariano Ruiz Jan 08 '18 at 13:05
14
vim <file-name>

:%s/$/,/g

To remove

:%s/,//g
Dharman
  • 30,962
  • 25
  • 85
  • 135
8

Keep it simple, just use awk:

$ awk '{printf "%s%s",sep,$0; sep=",\n"} END{print ""}' file
{...},
{...},
{...},
{...}
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • 8
    Keep it simple? The sed answer seems significantly simpler to me. – Kevin Jan 27 '16 at 00:20
  • No, it's just briefer. Think about the logic - find the last line and don't apply a substitution. What? It's like trying to use Prolog. Now try to enhance that to do just about anything else and you'll be knee deep in double negatives and bizarre convolutions of letters and punctuation marks before you know it. – Ed Morton Jan 27 '16 at 00:26
  • 2
    Sed: "every line except the last, find the end and add a comma." Simple. Awk: "every line print the separator and then the line, (wait, why the separator first?) then set the separator (why include the newline? Oh, must be a record separator...), then at the very end, print an empty line (what? Oh, the backwards RS/record printing doesn't leave a trailing newline)." You have an odd definition of "simple." – Kevin Jan 27 '16 at 00:48
  • You are trying to make this WAY more complicated than it is. None of the awk statements reads quite the way you state, and they all mean the same simple, obvious thing that's been programmed as such for decades in every Algol-based language (C, Pascal, Ada, whatever) - hold off on printing the end of line string until you print the subsequent line because that is when you know what to print at the end of the line. Nothing at all to do with "backwards RS" and "record printing doesn't leave a trailing newline". I guess we'll agree to disagree - happy sed-ing! – Ed Morton Jan 27 '16 at 01:43
  • 2
    You might need some conditional code in the END block to cater for empty files. – potong Jan 27 '16 at 17:42
  • Yup, couldn't hurt. If the OP wants it I can add that. – Ed Morton Jan 27 '16 at 17:49
  • 1
    The reason this is a little unintuitive is that it's taking advantage of the fact that `awk` doesn't care if a variable is undefined, it just treats it as empty. So, when the first line is processed, there is no 'sep', so you don't end up with a line at the beginning with just a comma on it (as you might expect from a simple reading of this script. – Josh Wright Jan 28 '19 at 16:47
  • 1
    This answer helped me A LOT because I'm already in an awk program, so the sed approach was not an option. Thanks, Ed! – Mark Melville Jul 20 '21 at 17:28