0

I want a non-perl solution where I should be able to append a single quote ' at the last visible (non-escape characters) line of a file and save it back to the file.

cat example.txt

var1: 'funn'
var2: 'weee'
var3: 'youuuu

Expected output

cat example.txt

var1: 'funn'
var2: 'weee'
var3: 'youuuu'

I know how to print the last line using awk and how to append a character at the end of each line but cannot get the file updated with appending the single quote only to the last line and updating the file.

Ashar
  • 491
  • @they it does not answer as i wish to append single quote and not replace string – Ashar Mar 27 '22 at 17:11
  • 1
    How is what you want to do different? Replacing the end of line with a single quote does sound like the same thing as replacing some string with another. – Kusalananda Mar 27 '22 at 17:18

1 Answers1

3

The sed expression $s/$/'/ adds a single quote to the end of the last line of input. The first $ is the "address" of the last line. When the last line is found, this triggers the given substitution, s, command. That command replaces the end of the line, matched by $ in the regular expression, with a single quote.

Would you want to perform the substitution only if the line does not already have a single quote at the end of it, then use $s/[^']$/&'/. This replaces the last character on the last line with itself, followed by a single quote, but only if that last character is not a single quote. Of course, this does require that there is at least one character on the line already.

In the shell, you can use these sed expressions in double-quotes, but you need to escape the two dollar signs from the shell:

sed "\$s/\$/'/" file
sed "\$s/[^']\$/&'/" file

If your sed supports it, you may use it with -i to perform an in-place edit on the file.

To apply this on only the last non-blank line in the file (and also delete the trailing blank-only lines), first, delete the blank lines at the end of the file. One way to do this is with the following pipeline:

tac file | sed '1,/[[:graph:]]/ { /[[:graph:]]/!d; }' | tac

This reverses the lines of the file with GNU tac, removes all lines up to the first non-blank line ("non-blank" meaning it has some graph character on it; you could use [^[:space:]] in place of [[:graph:]]), and then reverses the lines again.

Modifying the last line of this pipeline's output:

tac file | sed '1,/[[:graph:]]/ { /[[:graph:]]/!d; }' | tac |
sed "\$s/\$/'/" >file.new

Or, combining the two sed invocations:

tac file | sed "1,/[[:graph:]]/ { /[[:graph:]]/\!d; s/\$/'/; }" | tac >file.new

(Note the escaping of ! without which some shell may try to do a history expansion.)

... then just replace file with file.new using mv.

Kusalananda
  • 333,661