Search code examples
bashescapingquotessubstitution

Have bash interpret double quotes stored in variable containing file path


I would like to capture a directory that contains spaces in a bash variable and pass this to the ls command without surrounding in double quotes the variable deference. Following are two examples that illustrate the problem. Example 1 works but it involves typing double quotes. Example 2 does not work, but I wish it did because then I could avoid typing the double quotes.

Example 1, with quotes surrounding variable, as in the solution to How to add path with space in Bash variable, which does not solve the problem:

[user@machine]$ myfolder=/home/username/myfolder\ with\ spaces/
[user@machine]$ ls "$myfolder"
file1.txt file2.txt file3.txt

Example 2, with quotes part of variable, which also does not solve the problem. According to my understanding, in this example, the first quote character sent to the ls command before the error is thrown:

[user@machine]$ myfolder=\"/home/username/myfolder\ with\ spaces/\"
[user@machine]$ ls $myfolder
ls: cannot access '"/home/username/myfolder': No such file or directory

In example 2, the error message indicates that the first double quote was sent to the ls command, but I want these quotes to be interpreted by bash, not ls. Is there a way I can change the myfolder variable so that the second line behaves exactly as the following:

[user@machine]$ ls "/home/username/myfolder with spaces/"

The goal is to craft the myfolder variable in such a way that (1) it does not need to be surrounded by any characters and (2) the ls command will list the contents of the existing directory that it represents.

The motivation is to have an efficient shorthand to pass long directory paths containing spaces to executables on the command line with as few characters as possible - so without double quotes if that is possible.


Solution

  • Assuming some 'extra' characters prior to the ls command is acceptable:

    $ mkdir /tmp/'myfolder with spaces'
    $ touch /tmp/'myfolder with spaces'/myfile.txt
    
    $ myfolder='/tmp/myfolder with spaces'
    $ myfolder=${myfolder// /?}               # replace spaces with literal '?'
    $ typeset -p myfolder
    declare -- myfolder="/tmp/myfolder?with?spaces"
    
    $ set -xv
    $ ls $myfolder
    + ls '/tmp/myfolder with spaces'
    myfile.txt
    

    Here's a fiddle

    Granted, the ? is going to match on any single character but how likely is it that you'll have multiple directories/files with similar names where the only difference is a space vs a non-space?