3

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
Llewen
  • 31
  • 4
  • 3
    For debugging purposes, put `#!/bin/bash -vx` in the first line of your script – Basile Starynkevitch Dec 09 '19 at 13:12
  • [Pathname expansion](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_06) doesn’t happen within [double-quotes](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_03). It’s that simple. Note that it has nothing to do with neither curly brackets or `ls`. – Biffen Dec 09 '19 at 13:16
  • bash turns the double quotes into single quotes in that case? – Llewen Dec 09 '19 at 13:19
  • @Llewen No. Bash never turns any quotes into other quotes. What do you mean? – Biffen Dec 09 '19 at 13:20
  • When I ran the script with -vx it showd the command with single quotes around it, I guess that was just the output. – Llewen Dec 09 '19 at 13:22
  • Thank you Biffen, that clears that up. – Llewen Dec 09 '19 at 13:23
  • @Llewen That’s just a function of the `-x` printing. The arguments sent to the commands (`ls`, `echo`, etc) won’t have any quotes at all (in this case). – Biffen Dec 09 '19 at 13:23
  • Added find examples to the script. – Llewen Dec 09 '19 at 13:39
  • @Llewen Regarding `find`: In the first example neither the variable nor the asterisk will be expanded because of the single-quotes and `find` won’t find any files with `${File_name_prefix}` _literally_ in their name. The second example works but not why you think: The shell (Bash) doesn’t expand the asterisk and it gets passed as-is to `find` (inspect with `-x`), then `find` has logic to match it with filenames. The third example fails because the last token gets expanded into _multiple_ tokens and `find` doesn’t understand (compare to `find . -iname foo bar baz`). – Biffen Dec 09 '19 at 14:11

1 Answers1

0

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

oklas
  • 7,935
  • 2
  • 26
  • 42