Bash – Why does GNU Readline’s shell-expand-line command only expands the first occurrence of tilde (~)

bashreadline

According to the Bash manual, the shell-expand-line GNU Readline command should expand the command-line, just as Bash normally would, including alias and history expansion.

The current setting can be seen with bind -P | grep shell-expand-line:

shell-expand-line can be found on "\e\C-e".

My issue is that only the first tilde (~) is expanded in the example below:

~/foo/bar ~/foo/baz

After pressing "\e\C-e":

/Users/nlykkei/foo/bar ~/foo/baz

Why?

Best Answer

If you look at its source code, you'll see that shell-expand-line should be actually called shell-expand-line-as-if-it-were-a-word:

>> bashline.c
static int
shell_expand_line (count, ignore)
     int count, ignore;
{
     ...
      w->word = savestring (rl_line_buffer);
      w->flags = rl_explicit_arg ? (W_NOPROCSUB|W_NOCOMSUB) : 0;
      expanded_string = expand_word (w, rl_explicit_arg ? Q_HERE_DOCUMENT : 0);
>>> subst.c
/* Expand WORD, performing word splitting on the result.  This does
   parameter expansion, command substitution, arithmetic expansion,
   word splitting, and quote removal. */

WORD_LIST *
expand_word (word, quoted)
     WORD_DESC *word;
     int quoted;

Notice that that comment doesn't include either filename or tilde expansion. So it's basically a fluke that it works even for the first tilde (tilde only has meaning at the beginning of a word, anyway). But that will also do process substitutions, which isn't mentioned either. The heavy lifting is in the expand_word_internal function in the same file.

The rl_explicit_arg in the first snippet means that if you press Esc-1 or Alt-2 before the key combo bound to shell-expand-line, no quote removal and process/command substitution will be done. Pretty intuitive, isn't it?

You may try submitting a bug report, but there are probably already thousands of similar limitations and special cases like this in bash.

Related Question