linux command line find escape question mark

For some reason I would like to delete all files names like "*.jpg?" (the filename is ending with a real ?)

I tried this

find /var/www/ -type f -name "*.jpg\?"

and

find /var/www/ -type f -name "*.jpg?"

but this doesn't work how can i do that ?


Interestingly both of your commands work on the CentOS 6.5 find 4.4.2 system I have to hand. You can try using single quotes '

find /var/www/ -type f -name '*.jpg?'

If this works and it's available in your find, you can use the -delete argument to find to delete the files. This does away with the need for xargs and print0 and the like. Be sure to be ensure the find command works correctly before adding the the delete though.


Short answer:

find /var/www -type f -name '*.jpg\?'

Explanation:

? has a special meaning in most shells. It's the 'single character' wildcard.

On a shell, it means it will expand to any character, much like * expands to any string:

> echo *
1file 2file dir1 dir2 file1 file2
> echo ?
?
> echo file?
file1 file2

Keep in mind that this special characters will be expanded by your shell, not by the command you are passing them as arguments to.

In the specific case of find, find also accepts wildcards. Thus, you have to escape them on the shell in order for find to receive them.

Let me clarify that with another example:

> echo *
dir1 file1 file2
> find dir1 -name *
find: paths must precede expression: file1
> find dir1 -name \*
dir1
dir1/test1
dir1/test2
> find dir1 -name '*'
dir1
dir1/test1
dir1/test2

If I don't escape the *, find will receive the same string that the echo showed, instead of the *

As you can see, you can either escape special characters with backslash or surrounding them with ' single quotes. I prefer single quotes for many reasons. (Note that this applies for bash, dash, and maybe others, but probably not all).

Now you have escaped the ? from the shell but not from find. This will usually not cause trouble but it could if, for example, you have a file file.jpga you don't want to delete:

> find . -type f -name '*.jpg?'
./file1.jpg?
./file2.jpga
> find . -type f -name '*.jpg\?'
./file1.jpg?

Another choice would be find . -type f -name \*.jpg\\\?... now you see why I prefer single quotes.