Shell – Launch editor from a shell script with text

editorsshell-script

I know it is possible to launch the default editor from a shell script. For example, assuming the $EDITOR environment variable is set:

$EDITOR ~/newfile.txt

Is it possible to open a new file with pre-populated text?
One way I can think of is to create the file before opening it:

echo "Header" > ~/newfile.txt
$EDITOR ~/newfile.txt

But it would be slightly nicer if the file which the text editor opens is pre-populated, but also capable of being thrown away. Is this possible?

Best Answer

If you want to pre-populate content in the editor, write this initial content to the file, just like you thought.

There is no way to “put the editor in the state it would be in if you typed a few lines after opening it” that works across diverse editors. In many editors, this means that the file will be unsaved, but there's no uniform way to achieve that state, and there are editors that don't have this concept at all (e.g. Scratch).

You can however detect whether the file was saved at all from the editor. Abandon the operation if the file wasn't saved. To detect whether the file was saved, check its modification time before and after.

file=$(mktemp)
cat <<EOF >"$file"
Hello
world
EOF
old_metadata=$(ls -li "$file")
"${VISUAL:-"${EDITOR:-vi}"}" "$file"
new_metadata=$(ls -li "$file")
if [ "$new_metadata" = "$old_metadata" ]; then
  … # unchanged file, abandon operation
else
  … # modified file, carry on
fi

Beware that if the file was modified but the size and inode didn't change and the modification took less than 1 second, this script will think that the file hasn't been modified. This won't happen if a human is editing, but it could easily happen if $EDITOR is a script that submits a modified file automatically. It's difficult to do better in a portable way. With GNU coreutils, passing the --full-time option to ls solves this problem if the filesystem supports subsecond timestamps with sufficient precision.

Alternatively, check whether the file has been modified. The portable way of doing this is to keep a copy of the initial content and call cmp. If commands like sha256sum or sha are available, you can use these and compare the hashes before and after. You may still want to consider the file to have been edited if its timestamp has changed — maybe the user did want to submit the default input.

This technique is what several version control systems use when they launch an editor to edit a commit message. If the user doesn't save the file, the commit is aborted.

If you also want to place the cursor at the end of the input, there's no universal way to do that. With many editors, you can write

"$EDITOR" +"$line" "$file"

and the editor will open with the cursor on the specified line. This is supported by many editors including vi (all variants), emacs, joe and gedit, but not by kwrite.

Related Question