I have a .env file like


I want to replace the last noblank line with another file content

So far I have something like below:

{ (sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' local.env | sed '$d' local.env && printf "CONFIG=%s" "$(cat config.json | jq -c .)") >local.env.mod; } && mv local.env.mod local.env

Is there a better/simpler way to do this?

2 Answers 2


You could reverse the file and replace the first non-blank line

printf -v new_line 'CONFIG=%s' "$(jq -c . config.json)"

tac local.env \
| awk -v line="$new_line" '
      !n && /[^[:blank:]]/ {print line; n = 1; next}
  ' \
| tac > local.env.mod && mv local.env.mod local.env

I don't know about better (the best would be to know that it's the line that sets PARAM2 that needs replacing, but you specifically say "the last non-empty line"), but the ed editor is really good at applying editing procedures to text files that are too complicated for sed (but do note that it reads the full text into memory, unlike sed):

$ cat new-content
this is the new content
$ printf '%s\n' '?.? d' '-r new-content' ,p Q | ed -s file
this is the new content

The editing script that ed gets is

?.? d
-r new-content

This starts by searching backwards for the first line that contains anything (note that spaces count here, even though they are not visible; change the . to [[:graph:]] to only care about visible characters), and deletes it.

Deleting a line moves the cursor down to the line after, so the - in front of r tells ed to insert (read) the contents of new-contens on the line above where the cursor is.

The final ,p and Q displays the full document on standard output, and then quits the editor unconditionally. If you want to make an "in-line edit", change these two commands to the single wq command, which writes the modified document back to the file and quits.

To insert the contents of the new-content file after = in CONFIG=, replacing the end of the file, from the last non-blank line onwards:

$ printf '%s\n' '?[[:graph:]]?,$ c' 'CONFIG=' . 'r new-content' '-,.j' ,p Q | ed -s file
CONFIG=this is the new content

The c command changes lines, and we use it to replace the lines from the last non-empty line to the end. The input to the c command is ended with a single dot, and the content of new-content is inserted after with r. The j command joins the previous line (CONFIG=) with the line we just inserted (we assume it's a single line, because it is in your question).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .