Bash – Expansion Doubt

bashshell

If I'm in a folder and I want to find the jpg files, I can run

find -type f -name "*jpg"

but I don't understand why I have to use doble quotes. I know without them, pathname expansion will mess up the find command (if there is more than one jpg file in the folder), but do not know exactly why. I don't get too why here the quotes do not avoid expansion by the shell.

Best Answer

Both double and single quotes prevent filename expansion in the shell.

Find is somewhat special because it recurses through all the levels of directory.

If you do not quote the -name option in a find command, the shell expands the name expression immediately, in the directory where you run find. That may match the files zero times, one time, or many times.

For no shell matches, the *jpg just gets put back into the command line and passed to find as an option.

For one match, the actual name (e.g. K3256.jpg) is passed to find, which will therefore only look for files in lower directories with that exact name.

For multiple matches, several names will be put into the find command line, and find will refuse to run because the syntax of the arguments will be wrong.

Find itself takes on the responsibility of expanding the wildcard within each directory it descends into. It does not want any misplaced help from the shell.

Shell removes the quotes before invoking the find as a new process. This avoids all programs having to deal with quotes, which are strictly part of shell syntax. When the child process sees the args, they have been converted to an array of null-terminated strings, and do not need further adornment.

The find command understands and actions filename expansion in exactly the same way that shell does. The difference is that find descends through all the levels of directory, and in each directory it reads the list of names in there, and matches every name at that level against the -name pattern.

Note also that the -type f option also does its work within each sub-directory: the directory entries contain that information too, so find has to deal with both the file type and the name match all over again at every branch of the directory tree.

Also see this answer