Icicles - Shell-Command Enhancements

Previous: Icicles - Emacs Tags EnhancementsIciclesIciclesIndexNext: Icicles - Dired Enhancements

Icicles Shell-Command Enhancements

Icicles provides completion support for shell commands in these ways:

This section describes the optional Icicles completion available for `M-!’ and `M-|’. It applies also to completion for `!’, and `&’ in Dired (but those have additional enhancements).

In vanilla Emacs, when you enter a shell command at the prompt for `M-!’ or `M-|’, no completion is available for empty input, and non-empty input is completed only to an environment variable or to a shell command that is in your search path. For Emacs releases prior to Emacs 23, vanilla Emacs offers no completion at all.

In Icicle mode, `M-!’ and `M-|’ can, like vanilla Emacs (23 and later), complete using commands in your search path. This depends on the the value of option ‘icicle-guess-commands-in-path’ (see below).

Shell Command Completion as File-Name Completion

The most significant thing about Icicles completion for reading a shell command is that it is in fact file-name completion. Reading a shell command means, first, reading a file name. This is unexpected, to say the least.

Because of this unusual behavior, this feature is optional and is not enabled by default. To enable it, customize option `icicle-functions-to-redefine’ to add the shell-related functions ‘dired-read-shell-command’ and ‘read-shell-command’. If you do that, then Icicle mode will substitute Icicles functions for these standard functions and you will get the Icicles completion described here.

A shell command is itself an executable file, either a binary program or a script. That’s not so shocking. But since Icicles uses file-name completion for your entire shell-command input, including any switches (options) and command arguments, all of that input is interpreted by ‘read-file-name’ as a file name, before it gets passed on to the shell.

The reason for optionally providing file-name completion for a shell command is to let you easily invoke a program no matter where it resides, whether or not its directory is in your search path. You can use completion to navigate to the command’s location.

Icicles shell-command completion is lax, so you can enter any command you want, not just a file-name completion candidate. And you can edit the completed input before hitting ‘RET’, to add command switches (options) and arguments. The overall input string is taken as a (pseudo) file name, but it is then passed to the shell for execution.

One drawback to this approach of using file-name completion is that the history list is the file-name history, not the history of previous shell commands.

Gotcha: `$' in Shell Commands

There is a gotcha, however, regarding `$’ and file-name input:

When you hit ‘RET’ to accept the input, ‘read-file-name’ finishes its job, as always, by trying to expand any environment variables in the string. Usually this is what you want, and it presents no problem. But in the context of a shell another `$’ syntax is also used. For example, `$1’ typically means the first argument or first field; it does not mean a variable named ‘1’.

‘read-file-name’ knows nothing about this different `$’ syntax, and it systematically calls ‘substitute-in-file-name’ to expand any environment variables in the file name you enter (when you hit ‘RET’). It interprets `$1’ the same way it inteprets `$PATH’, treating ‘1’ as an (unknown) environment variable. This is not what you want it to do. If you input `awk '{print $1}’ Emacs raises this error:

  Substituting nonexistent environment variable "1"

What can you do about this? Three possible approaches:

Known Shell Commands as Proxy Candidates

If you do turn on Icicles file-name completion for reading shell commands, then extra, known shell commands are also made available as proxy completion candidates, provided that option `icicle-guess-commands-in-path’ is non-‘nil’ (it is ‘nil’ by default). These extra candidates are the names of all executable files (or of all files, if ‘shell-completion-execonly’ is ‘nil’) in your search path.

The fact that these are Icicles proxy candidates means that they are available regardless of the current default-directory – they are not in fact treated as file-name candidates, even though they are available during file-name completion. You can easily recognize Icicles proxy candidates in buffer ‘*Completions*’: they have face ‘icicle-proxy-candidates’. See Proxy Candidates.

If ‘icicle-guess-commands-in-path’ is non-‘nil’, the list of search-path candidate commands is computed once and cached as the value of `icicle-shell-command-candidates-cache’. The particular non-‘nil’ value of ‘icicle-guess-commands-in-path’ determines when the cache is filled. If the value of ‘icicle-guess-commands-in-path’ is ‘first-use’, the cache is filled the first time you use it, and each time you turn on Icicle mode it is updated. If the value of ‘icicle-guess-commands-in-path’ to is ‘load’, then the cache is instead filled each time you load Icicles.

Regardless of the non-‘nil’ value of ‘icicle-guess-commands-in-path’, if you save ‘icicle-shell-command-candidates-cache’, then that value is used in future sessions (no delay for searching your path).

If your environment changes, you can use command ‘icicle-recompute-shell-command-candidates’ to update the cached list at any time. With a prefix argument, the updated value is saved persistently.

In addition to the extra candidates computed by searching your search path, in contexts such as Dired where target (e.g. marked) files for the shell command are known, the extra candidates include additional commands (possibly including switches) that Icicles can guess might be appropriate for the target files. See Shell Commands on Marked Files.

During Icicles shell-command completion, help is available for individual candidates, using ‘C-M-RET’, ‘C-M-mouse-2’, and so on. For an extra candidate, help is provided for the command by the ‘apropos’ shell command (if available). For a file-name candidate, help shows the file’s properties. See Icicles - Help on Candidates.

Using On-Demand Completion with Shell-Command Input

Even if you do not choose to turn on the file-name completion feature described above, you can still get file-name completion when you input a shell command. Just do it on the fly, using ‘C-M-S-f’ (aka ‘C-M-F’).

After you have typed or completed the shell command per se (e.g. a file name or a search-path command), you can use ‘C-M-F’ to complete (relative) file names to insert as shell-command arguments as part of the command line to submit to the shell. See Icicles - Completion On Demand.

In addition, remember that you can use ‘M-o’ anytime in the minibuffer to complete against a previous input. This means that if you have previously entered some complex shell command (e.g. with various switches or arguments), then you can use ‘M-o’ to retrieve it for reuse (possibly editing it). See Using Completion to Insert Previous Inputs: `M-o'.

In addition, you can use ‘C-M-pause’ to switch to another history, then use ‘M-o’ to complete against that history. And you can do this as many times as you like during the same overall shell-command input. You can thus use different histories to compose different parts of the overall command. See Using Other Histories; Commands Any Which Way.

None of this is special to shell-command input. ‘C-M-F’, ‘C-M-pause’, and ‘M-o’ are all available in Icicle mode for any minibuffer input.

Previous: Icicles - Emacs Tags EnhancementsIciclesIciclesIndexNext: Icicles - Dired Enhancements

DrewsElispLibraries referenced here: Lisp:icicles.el

CategoryCommands CategoryCompletion CategoryRegexp CategoryModes CategoryProgrammerUtils CategoryCode CategorySearchAndReplace CategoryShell CategoryRegion