Search code examples
bashvariablesdouble-quotesexpansionpathname

Why does this combination of curly braces and double quotes not work in bash?


I'm trying to understand how to use curly braces and quotes properly in bash. I'm wondering why the third example of an ls command doesn't work.

#!/bin/bash -vx

# File name prefix.
File_name_prefix='this_is_a_file_name_prefix'

# Let's do this in the /tmp directory.
cd /tmp

# Let's make three empty files.
touch ${File_name_prefix}_1.txt
touch ${File_name_prefix}_2.txt
touch ${File_name_prefix}_3.txt

# Let's list the three files.

# This works.
ls "$File_name_prefix"*
# This works.
ls ${File_name_prefix}*
# This does not work.
ls "${File_name_prefix}*"

# This fails.
find ./ -type f -name '${File_name_prefix}*'
# This fails spectacularly.
find ./ -type f -name ${File_name_prefix}*
# But this works.
find ./ -type f -name "${File_name_prefix}*"

echo "Why?"

# Clean up.
rm ${File_name_prefix}*

exit

Solution

  • When you execute a command like first and second examples:

    ls "$File_name_prefix"*
    ls ${File_name_prefix}*
    

    Command interpreter actually execute a command with interpolation according to directory content. A directory is used from command line itself or current directory is used (if command line has relative path),

    so it executes like this (assume $File_name_prefix is fp and directory has files fp1 fp2 fp3):

    ls fp1 fp2 fp3
    

    But for third example command interpreter consider quoted argument as ready to use and do not applies * interpolation.

    so it executes like this:

    ls "fp*"
    

    And because there is no file with name fp* (with asterisk in name) but only files fp1 fp2 fp3 (as we assumes) in the directory, therefore it show empty list or says that there is no such file or directory