I was playing around with the readline functions shell-expand-line and alias-expand-line. From the documentation:

shell-expand-line Expand the line as the shell does. This performs alias and history expansion as well as all of the shell word expansions (see Shell Expansions).

My understanding of this is that shell-expand-line would perform all substitutions and expansions that bash would before the point of actual execution.

A contrived example seems to support this:

$ NAME="Adam"
$ alias ec='echo'
$ ec $NAME

If I execute the function shell-expand-line the previous command expands to $ echo Adam.

Where my confusion begins is with the following example:

$ alias cdspace='cd ~/path\ with\ spaces'
$ cdspace

Based on my understanding if I were to execute shell-expand-line the command would expand to $ cd /Users/Adam/path\ with\ spaces. However in practice it expands to $ cd ~/path with spaces. Executing cdspace either as is, or with alias-expand-line works as expected, however if I expand it with shell-expand-line execution fails.

The sub-section Quote Removal of Shell Expansions does address this:

After the preceding expansions, all unquoted occurrences of the characters ‘\’, ‘'’, and ‘"’ that did not result from one of the above expansions are removed.

So it seems like unquoted backslashes are always removed. To test this, if I manually type $ cd ~/path\ with\ spaces and then execute shell-expand-line it updates the command to $ cd ~/path with spaces. Furthermore, if I type $ cd ~/path\\ with\\ spaces and then execute shell-expand-line twice each execution it removes one set of of back slashes.

My expectation is that shell-expand-line fully expands the line to what would be ultimately resolved by bash internally, but this does not seem to be the case as it needs to be executed multiple times.

Where I am ultimately confused now is how $ cd ~/path\ with\ spaces correctly executes as by my understanding of the Shell Expansions documentation, it will eventually be resolved to $ cd ~/path with spaces.

  • 1
    Apparently, the doc is not accurate about shell-expand-line, as shown in this other question on U&L.
    – fra-san
    May 29 '20 at 21:45
  • Setting tilde expansion aside: are you saying that, in your expectations, the /p w s path with spaces needs to be resolved by Bash into /p\ w\ s (including the backslashes), at the end of the steps listed in the "Shell Expansions" section of the manual, to work correctly?
    – fra-san
    May 29 '20 at 22:05
  • I'm saying the opposite, that (to my understanding of the documentation at least) after all the other steps of expansion and substitution, bash will remove the escaped spaces such that /p\ w\ s will get resolved to /p w s, and the behavior of shell-expand-line seems to support this.
    – atommclain
    May 29 '20 at 23:45
  • run bash -x script.sh and see differences between single and double quotes for alias on debugging output
    – alecxs
    May 31 '20 at 11:06

I think the bash documentation is unclear here. As noted in another comment, the shell-expand-line documentation implies that all Shell Expansions will be executed, when clearly tilde expansion is not.

Additionally, the Quote Removal step does not remove unquoted backslashes still lingering after the first set have been pattern matched, contrary to what 3.5.9 (https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Quote-Removal) indicates.

That said, I don't think shell-expand-line is intended to produce a command that can be run from the shell, if that is what you're expecting. Because it is performing all the Shell Expansions, which assume the input has already been tokenized, the pattern matching step will remove backslashes, making the previously escaped spaces 'unescaped.' If you try to run the resulting string, it will be tokenized again, and thus each space-separated word will be treated as a separate token.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.