BatchMode

[For the Emacs mode for editing DOS batch files, see DosScripts.]

According to the EmacsManual:

The command-line option ‘-batch’ causes Emacs to run noninteractively. In this mode, Emacs does not read commands from the terminal, it does not alter the terminal modes, and it does not expect to be outputting to an erasable screen. The idea is that you specify Lisp programs to run; when they are finished, Emacs should exit. […]
Any Lisp program output that would normally go to the echo area, either using ‘message’, or using ‘prin1’, etc., with ‘t’ as the stream, goes instead to Emacs’s standard error descriptor when in batch mode. Similarly, input that would normally come from the minibuffer is read from the standard input descriptor. Thus, Emacs behaves much like a noninteractive application program. […]

The EmacsManual does not give any examples so here are a few.

Basics

You can call simulate an EmacsLisp-based script by putting this in a batch script:

emacs -batch -l ~/.emacs.editor --eval="(require 'foo)" \
--eval="(require 'bar)" \
--eval="(some-function $*)"

Starting with the Emacs 22, you can write Emacs scripts just as if you were writing Bash or Perl scripts, when you include this at the top of your script file:

#!/usr/bin/emacs --script

Error codes

One use of batch scripting is to run a predicate over a collection of files. For example, to use ‘check-parens’ and exit with an error code 1 if ‘check-parens’ throws an exception:

emacs file --batch --eval="(condition-case nil (check-parens) (error (kill-emacs 1)))"

Easily turned into a shell script to print out the names of files with detected imbalances:

for file in *.txt; do emacs "$file" --batch --eval="(condition-case nil (check-parens) (error (kill-emacs 1)))" &> /dev/null || echo $file; done

Indenting C files

  emacs -batch sample.c --eval '(indent-region (point-min) (point-max) nil)' -f save-buffer

The above opens the file sample.c and runs ‘indent-region’ from the beginning (‘point-min’) to the end (‘point-max’) of the file, then saves the file. Because Emacs is thoughtful, it automatically saves a copy of the original file to sample.c~.

Filling Paragraphs

Emacs is provided with an intelligent paragraph filling command, which can be helpful for use on numerous files. To have Emacs fix the long lines of one or more files from the command-line, use the following command:

  emacs -batch long-file.txt --eval '(fill-region (point-min) (point-max))' -f save-buffer

Emacs will use the filling rules for the mode the file is opened in, and fill all lines in the file. This could have unexpected results in certain modes.

Here is a link to a script that wraps up the command so it can be conveniently used on the command line with command line arguments:

Texinfo Files

Emacs can, from the command-line, update or insert Texinfo menus and nodes in a Texinfo document using the ‘texinfo-every-node-update’ and ‘texinfo-all-menus-update’ commands. This is especially helpful when a Texinfo file is being generated or converted from another source document. Consider the following MakeFILE? rule which can convert some OTHER format into Texinfo (where OTHER is some other document format like XML or HTML):

  %.texi: %.other $(OTHER2TEXI)
          $(OTHER2TEXI) $< > $@
          emacs -batch $@ \
           -f texinfo-every-node-update -f texinfo-all-menus-update \
           -f save-buffer

Shell Script

The example script shs-example demonstrates all the things you’d want to do with emacs scripts, and is meant to serve as a tutorial (I am teaching myself and improvements are very welcome) as well as demonstrate some useful functions from shs.el. Save these files somewhere in your bash path, change the path to that path in example-emacs-script and change the “#/usr/local/bin/emacs” address call to that of your actual Emacs path. Then, on bash prompt, type example-emacs-script.

If active Emacs developers are reading this, we’d like to point out that (princ) in batch-mode prints to stdout, as opposed to stderr, which is not what the EmacsLispReference says. On the other hand, that is the only way at this time (we think) that you can print to stdout through an emacs batch script, so we hope that this “bug” is not fixed, but retained as a feature.

This is not a bug. princ function and all the print functions) direct their output depending on the variable standard-output. This variable can be set to a buffer, a marker, any function of 1 argument or the symbol t. The last case is the default. In interactive mode the output goes to the echo area. In batch mode it is directed to the normal stdout. The message function prints to stderr in batch mode. Perhaps there is an error in the documentation you referenced above (I have not checked)

Prompts in w32 cmd-files

Example:

@"c:\Program Files\Emacs\emacs-21.3\bin\emacs.exe" -batch -no-site-file -q ^
  -eval "(unless (y-or-n-p \"Do you want to continue? \") (kill-emacs 1))

@if %errorlevel% GTR 0 goto fin

Using packages in your script

Emacs batch mode does not read your personal config (or any config, it’s equivalent to -Q) so you don’t get packages loaded.

You can do whatever you were going to do though, just {{{package-initialize}}} when you eval. Here’s how I build packages using ElpaKit, which is itself a package:

emacs -batch --eval '(progn(package-initialize)(elpakit-make-multi "~/work/elmarmalade"))'

Nothing else special is required, except the package directory (which is {{{~/.emacs.d/elpa}}}) to be in the normal place.

It does seem that this would be a useful additional startup option, batch but with your packages and not your config.

Discussion

We need a term more descriptive than “scripting” for this, since some people think that writing an emacs package is scripting. “batch mode” kind of implies no interactivity, which isn’t true. “command line or executable scripting with emacs lisp” is a mouthful. Maybe “scripting” is the best.

Scripting is within a hair of opening up a huge new market for emacs. People who use bash or Python or whatever could be using emacs:

  • you’re already using it
  • it’s lisp
  • it’s pretty cl compatible
  • it’s already installed
  • it’s portable
  • it does everything
  • it won’t go away
  • it supports unique features like buffers
  • you can record a keyboard macro and save the script

The EASILY FIXABLE THINGS holding it back are:

  • fear that emacs lisp isn’t a real language (as if bash were)
    • some people don’t know about (require ‘cl) or lexical-let
  • uncertainty about whether it will handle stdio and the like
    • how to get rid of “Loading” messages?
    • how to pipe something to a command and back to emacs lisp?
    • is “a few minor exceptions” above famous last words?
  • doubt that this usage will be supported
    • see note about princ above
    • no detailed discussion in documentation
    • paucity of open source shebang scripts

Does anybody agree? Drop me a line just to let me know somebody read this.

(gambarimasu who is at gmail.com)

See also

See also EmacsScripts.


CategoryCode