Function of single quotes is unclear

I’m confused about the following code from the Glob Pattern command line exercises:

find /home -name '?q'

Which returns:

/home/dq

My understanding of the single quotations from earlier in the lesson is that when used in conjunction with wildcards like ‘?’, they act as an escape. In this case, the expected behavior of the search would not yield the result indicated, because the file being searched for would be ‘?q’ literally (in other words, a file whose name is two characters long: first character a question mark, second character a lowercase q).

Why does this functionality of single quotes suddenly cease here?

We escape a character by using the backlash \ or the single quote ' '. This example if for a case where someone came up with the great idea of naming a file using special characters.

Yes, but suppose we wanted to search for a file called ?q (with a special character). Would that search syntax be:

find /home -name '\?q'

I guess I’m just confused why the single quotes don’t make it search for a ‘?’ in the file name.

It is either \?q or '?q'.

You search for a file named \?q with this '\?q'.

1 Like

Nicely spotted. This one of the reasons why in the content I simplified specifically as follows.

A simplified usage of this command looks like find [location] -name ['filename'] .

Note the single quotes in filename. They’re always supposed to be there, they’re part of the (simplified) usage of the command. They’re not acting with the same function as when using glob patterns to match filenames.

Glob patterns are used to match filenames as arguments of commands. What we’re passing to find is a pattern, not actual file names.

I’ll try to clarify this below. We’ll make use of the command echo !$; the argument !$ is the last argument(s) of the previous command.

Here’s an example.

$ cal -m 3
    Março 2020       
do se te qu qu se sá  
1  2  3  4  5  6  7  
8  9 10 11 12 13 14  
15 16 17 18 19 20 21  
22 23 24 25 26 27 28  
29 30 31              
                     
$ echo !$
echo 3
3

I ran cal -m 3, which shows the calendar for the third month of the current year. The argument 3 is the last argument in the command, and as such the second line of echo !$ is 3.

Let’s setup a mini environment first. We’ll create a directory and files called dq and ?q in that directory.

$ mkdir mcriotto
$ cd mcriotto
$ touch dq '?q'
$ ls
dq  '?q'

We’ll now run ls ?q, which we expect to list the same files as above, and then check the previous argument.

$ ls ?q
dq  '?q'
$ echo !$
echo ?q
dq ?q

As you can see, the last argument isn’t ?q, but rather the filenames which the pattern ?q matches.

Now let’s search for these very same files using the same pattern.

[email protected]:/media/HDD Disk/Scratch/mcriotto$ find . -name '?q'
./dq
./?q

And let’s check the last argument.

$ echo !$
echo '?q'
?q

So you see that the last argument of the find command we ran is the pattern itself, where as for ls it was the actual filenames.

To address this, that’s because find takes patterns as inputs, not filenames. To draw a parallel with ls, ls takes filenames as input, so the shell expands the pattern to match the file names, ls never sees the pattern, where as find sees exactly the pattern.

I hope this helps.

5 Likes

Excellent and thorough explanation. Thanks Bruno!

1 Like