0

I'm new to Bash. From the Finding Files documentation:

You want to find every file in ~/mydir and all its subdirectories, recursively, with a file extension of .htm (or .HTM or .Htm...) and delete it. I've seen a lot of attempts like rm -rf ~/mydir/*.htm which really don't come close. The correct solution is

find ~/mydir -iname '*.htm' -exec rm {} \;

-iname says that you want to do a case-insensitive search on the filename. '*.htm' is in single quotes to prevent bash from expanding the *, which will produce unexpected results.


Question: What does asterisk produce with and without the quotes? Why would you decide to use quotes versus not?

1
  • If you really would like to delete files, you would use find ~/mydir -iname -type f "*.htm" -delete, since Ubuntu uses gnu-find, which has the handy -delete switch. Simpler for typing, and find will, if you omit the -type f restriction, start a deep-first-search, and eventually delete empty directories, too. Mar 4, 2018 at 18:29

3 Answers 3

1

Without quotes, the shell expands *.htm to a list of files and passes this list to find. With quotes, the shell provides the five character string *.htm as an argument to find.

For example, with quotes:

$ ls
a.htm  b.htm
$ echo find . -iname '*.htm'
find . -iname *.htm
$ find . -iname '*.htm'
./b.htm
./a.htm

The above works as desired. Without quotes, find is given arguments that it does not know how to process:

$ echo find . -iname *.htm
find . -iname a.htm b.htm
$ find . -iname *.htm
find: paths must precede expression: b.htm
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
0

How about an example first, here we are looking for all files with .htm extension (case insensitive) recursively :

$ tree 
.
├── spam
│   ├── egg.htm
│   └── egg.Htm
├── spam.htm
└── spam.Htm


$ find . -type f -iname *.htm
./spam.htm
./spam.Htm

$ find . -type f -iname '*.htm'
./spam.htm
./spam/egg.htm
./spam/egg.Htm
./spam.Htm

As you can see in the first case where i have not used any quoting -iname *.htm, the filename has been subjected to glob (*) expansion first (done by shell, before find starts) as i have not used any quote and result in :

find . -type f -iname spam.htm spam.Htm

i.e. all files in the current directory having an extension .htm (case insensitive). As a result although ./spam subdirectory has two files with .htm extension but they won't be found as we are now looking for files spam.htm or spam.Htm.

On the other hand in the second case find . -type f -iname '*.htm', we have used quoting so the filenames won't be subjected to glob expansion hence we will get the desired result.

0

I believe what you are seeking to understand is a process called Quoting. Quoting works with double quotes and single quotes.

If you place text inside double quotes, all special characters used by the shell lose their meaning, except $ (dollar sign), \ (backslash), and ` (back tick).

Single quotes suppress all expansions.

Escaping Characters are also something to be given attention in such situations. You can precede a character with a \ (backslash) to turn it into an Escaping Character. This is often done inside double quotes to selectively prevent an expansion.

echo "This bowl costs \$10.00"
This bowl costs $10.00

Here $ would be said to be the Escape Character.

Not the answer you're looking for? Browse other questions tagged .