Opening default text editor in Bash?
The user's chosen editor should be in $EDITOR
, but you must still choose a sane default.
"${EDITOR:-vi}" file.txt
How to open the default text editor in Linux?
There is no completely reliable concept of "default editor" on Linux, let alone more broadly Unix-like systems.
Traditionally, users would set the environment variable EDITOR
to the path of their editor of choice. If this variable is set, I'm thinking you can be reasonably confident that they will know how to use it, even if they end up in something horrible like nano
.
A slightly newer convention is to set VISUAL
to the preferred "visual editor" - I guess the terminology comes from vi
to contrast against line editors like ed
.
${VISUAL-${EDITOR-nano}} path/to/new/file.txt
On Debianish systems, the system default editor is configurable via alternatives
and available simply with the command editor
.
On XDG systems, of course, you could simply
touch path/to/new/file.txt
xdg-open path/to/new/file.txt
Needless to say, this only works if you have XDG, i.e. In practice a Linux (or maybe modern *BSD) platform with an active graphical session (excludes Mac and pre-XDG graphical systems as well as of course any server environment where there is no GUI).
As an aside, if I can guess even roughly what your script does, it could probably be pared down to a fairly simple sed
script. Remember, sed
can do (almost) everything grep
and tail
can. Maybe see also Combining two sed commands - here is a quick and dirty refactoring.
cd /usr/share/applications
$(sed -n "s:^Exec=\([^%]*\)\(%.\(.*\)\)*:\1\3:p" "$(sed -n "s:^$1=::p" defaults.list | tail -1)" | tail -1) &
However, from quick googling, it looks like /usr/share/applications/defaults.list
is specific to OpenDesktop environments; but it's the system-wide default default - the admin could have installed an override in a different location, and individual users probably have individual preferences on top of that. Finding and traversing this hierarchy is precisely what xdg-open
does, so I'm not going to try to reimplement it in an ad-hoc script of my own, and suggest you shouldn't, either.
There is nothing about graphical environments in your question, so it's unclear whether you are actually looking for a simple editor for beginners who barely know how to click and drool in a graphical environment (in which case I'd say go with touch
followed by xdg-open
) or a competent programmers' editor which way or may not run in a window (maybe try VISUAL
with fallback to EDITOR
, and document that you use this mechanism).
Python3/Linux - Open text file in default editor and wait until done
Instead of trying to poll a PID, you can simply wait for the child process to terminate, using subprocess.Popen.wait()
:
Wait for child process to terminate. Set and return returncode attribute.
Additionally, getting the first part of get_commandline()
is not guaranteed to be the launcher. The string returned by get_commandline()
will match the Exec
key spec, meaning the %u
, %U
, %f
, and %F
field codes in the returned string should be replaced with the correct values.
Here is some example code, based on your xdg-mime
approach:
#!/usr/bin/env python3
import subprocess
import shlex
from gi.repository import Gio
my_file = 'test.txt'
# Get default application
app = subprocess.check_output(['xdg-mime', 'query', 'default', 'text/plain']).decode('utf-8').strip()
# Get command to run
command = Gio.DesktopAppInfo.new(app).get_commandline()
# Handle file paths with spaces by quoting the file path
my_file_quoted = "'" + my_file + "'"
# Replace field codes with the file path
# Also handle special case of the atom editor
command = command.replace('%u', my_file_quoted)\
.replace('%U', my_file_quoted)\
.replace('%f', my_file_quoted)\
.replace('%F', my_file_quoted if app != 'atom.desktop' else '--wait ' + my_file_quoted)
# Run the default application, and wait for it to terminate
process = subprocess.Popen(
shlex.split(command), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
process.wait()
# Now the exit code of the text editor process is available as process.returncode
I have a few remarks on my sample code.
Remark 1: Handling spaces in file paths
It is important the file path to be opened is wrapped in quotes, otherwise shlex.split(command)
will split the filename on spaces.
Remark 2: Escaped %
characters
The Exec
key spec states
Literal percentage characters must be escaped as %%.
My use of replace()
then could potentially replace %
characters that were escaped. For simplicity, I chose to ignore this edge case.
Remark 3: atom
I assumed the desired behaviour is to always wait until the graphical editor has closed. In the case of the atom text editor, it will terminate immediately on launching the window unless the --wait
option is provided. For this reason, I conditionally add the --wait
option if the default editor is atom.
Remark 4: subprocess.DEVNULL
subprocess.DEVNULL
is new in python 3.3. For older python versions, the following can be used instead:
with open(os.devnull, 'w') as DEVNULL:
process = subprocess.Popen(
shlex.split(command), stdout=DEVNULL, stderr=DEVNULL)
Testing
I tested my example code above on Ubuntu with the GNOME desktop environment. I tested with the following graphical text editors: gedit, mousepad, and atom.
C++ (Unix): Open a text file with the default editor
There is no official solution. Here is my recommendation for opening up a text editor:
If the filename extension is .txt
, and xdg-open
is avaliable on $PATH
and the $DISPLAY
variable is nonempty, then use xdg-open
. Otherwise use /usr/bin/sensible-editor
if it exists. Otherwise, use getenv("EDITOR")
, getenv("VISUAL")
or getenv("SELECTED_EDITOR")
. If none of them are set, try nano
, nano-tiny
and then vi
.
Linux Open default terminal text editor
If the system is properly configured, editor
should do the job.
For instance, on my debian system, editor is configured to use nano.
$ update-alternatives --display editor
editor - auto mode
link currently points to /bin/nano
/bin/nano - priority 40
slave editor.1.gz: /usr/share/man/man1/nano.1.gz
/usr/bin/emacs23 - priority 0
slave editor.1.gz: /usr/share/man/man1/emacs.emacs23.1.gz
/usr/bin/vim.basic - priority 30
slave editor.1.gz: /usr/share/man/man1/vim.1.gz
slave editor.fr.1.gz: /usr/share/man/fr/man1/vim.1.gz
slave editor.it.1.gz: /usr/share/man/it/man1/vim.1.gz
slave editor.pl.1.gz: /usr/share/man/pl/man1/vim.1.gz
slave editor.ru.1.gz: /usr/share/man/ru/man1/vim.1.gz
/usr/bin/vim.tiny - priority 10
slave editor.1.gz: /usr/share/man/man1/vim.1.gz
slave editor.fr.1.gz: /usr/share/man/fr/man1/vim.1.gz
slave editor.it.1.gz: /usr/share/man/it/man1/vim.1.gz
slave editor.pl.1.gz: /usr/share/man/pl/man1/vim.1.gz
slave editor.ru.1.gz: /usr/share/man/ru/man1/vim.1.gz
Current 'best' version is '/bin/nano'.
I was expecting it to use the environnement variable EDITOR, but obviously it's not the case, at least on Debian.
How do I use Rust to open the user's default editor and get the edited content?
I could be wrong, but I think the way git commit
works is that it creates a temporary file (.git/COMMIT_EDITMSG
) and then as a sub-process it opens that file in the user's $EDITOR
and then waits for the editor's process to exit/return. That will only happen when the user closes their editor. Which basically means that they can use the full power of their choice of editors, i.e. navigate in the file, save their changes, etc.
Thus, in Rust, you could use std::process::Command
to open the user's editor, which you can get via the std::env::var
. You can store the temporary file in a specific location if your application has one (like the .git
directory for git
or ~/.config/<your-app>/<your-file>
, etc.) or you could create a temporary one inside the system's temporary directory returned to you by the std::env::temp_dir
. (Alternatively you could use the excellent third party crate to directly create a temporary file only: tempfile
)
Here's a working example using the above mentioned technique:
use std::{
env::{temp_dir, var},
fs::File,
io::Read,
process::Command,
};
fn main() {
let editor = var("EDITOR").unwrap();
let mut file_path = temp_dir();
file_path.push("editable");
File::create(&file_path).expect("Could not create file");
Command::new(editor)
.arg(&file_path)
.status()
.expect("Something went wrong");
let mut editable = String::new();
File::open(file_path)
.expect("Could not open file")
.read_to_string(&mut editable);
println!("File content:\n{}", editable);
}
How can I open a file with the standard text editor?
You can use the open
crate. It supports Windows, OS X and Linux. To open a text-file on your C:
drive, you can use
extern crate open;
fn main() {
open::that("C:\textfile.txt");
}
Subversion CLI default text editor on Linux
When you download the source directly (and build it - assuming you have the build dependencies met) you specify (or you can omit it) the default fallback editor. Normally source builds are done with something like this on Ubuntu (assume I have extracted/downloaded the subversion 1.8.10 source from here):
./configure
make
sudo make install
Notice the ./configure
command above doesn't specify any options. The defaults will install to the prefix /usr/local . Prior to issuing those commands (on Ubuntu 12.04) I ran sudo apt-get build-dep subversion
. I then did the commands above to build and install. I made sure that options 1-5 (In the OPs question) were not satisfied and then tried to commit a change to a repository. I got this as a response:
svn: E205007: Commit failed (details follow):
svn: E205007: Could not use external editor to fetch log message; consider setting the $SVN_EDITOR environment variable or using the --message (-m) or --file (-F) options
svn: E205007: None of the environment variables SVN_EDITOR, VISUAL or EDITOR are set, and no 'editor-cmd' run-time configuration option was found
Since I didn't remove the official Ubuntu subversion I had to run mine as /usr/local/bin/svn
to make sure I was using the one I built. I could have used sudo apt-get remove subversion
to remove the official one as well just to make sure.
Now if one runs these commands to rebuild the source:
make clean
./configure --with-editor=/usr/bin/editor
make
sudo make install
One should find that if options 1 to 5 are not satisfied and this version of subversion is run it should default to running whatever /usr/bin/editor
points to. On Ubuntu that will depend on what alternative is being used.
So when Ubuntu does an official build where does their fallback editor come from? I went to the 12.04 source repository for subversion at this link . On the right hand side I downloaded the diff file subversion_1.6.17dfsg-3ubuntu3.4.diff.gz . I opened up the diff file Ubuntu uses and scrolling down you can find they use this set of ./configure
options (flags):
confflags := \
--prefix=/usr \
--libdir=$(libdir) \
--mandir=\$${prefix}/share/man \
--with-apr=/usr \
--with-apr-util=/usr \
--with-neon=/usr \
--with-serf=/usr \
--with-berkeley-db=:::db \
--with-sasl=/usr \
--with-editor=/usr/bin/editor \
--with-ruby-sitedir=/usr/lib/ruby \
--with-swig=/usr \
--with-kwallet \
--with-gnome-keyring
The bold entry shows that they use /usr/bin/editor
as their fallback.
I have built subversion 1.8.10 from source on Ubuntu 12.04 and got the expected behavior. This suggests one of these possibilities:
- On one of the systems the options 1 through 5 is actually met.
- One version of subversion was built with the
--with-editor
configure flag (either directly or indirectly). The fallback would point to whatever the--with-editor
configure flag was set to. - On one of the systems the wrong version of subversion is being run. One possibility is that the official subversion on Ubuntu is in fact being used. If that is the case it was built to use
/usr/bin/editor
as a fallback. - On one of your systems you have an alias (or equivalent) for
svn
that specifies an editor. Aliases would be specified in a startup script like~/.bashrc
,~/.bash_profile
,/etc/bash.bashrc
for example.
Related Topics
Sending Realtime Signal from a Kernel Module to User Space Fails
Overview/Reference Manual for Open Firmware Device Trees
Time Taken by 'Less' Command to Show Output
Find Ip Address of My System for a Particular Interface with Shell Script (Bash)
Assembly Divisions and Floating Points
Hugo Version Not Updating to Latest
Grep Array Parameter of Excluded Files
Moving a Git Repo to Another Server
Conversion from Ebcdic to Utf8 in Linux
Why Does High-Memory Not Exist for 64-Bit Cpu
When to Use Linux Kernel Add_Timer Vs Queue_Delayed_Work
Cvs Tab Completion for Modules Under Linux
Linux: Changing File Ownership Without a Copy
Linux User Space Threads, Kernel Threads, Lightweight Processes