Quoting And Filename Handling In Find -Exec
The Pitfalls of Quoting and Special Characters in find -exec
The find command in Linux allows users to search for files matching certain criteria and then perform actions on those files using the -exec option. However, properly quoting arguments and handling special characters in filenames can be tricky when using -exec.
If arguments are not quoted properly, find may interpret them incorrectly, leading to errors or unexpected behavior. Additionally, filenames often contain spaces, wildcards, and other special characters that need escaping in order for commands run by -exec to work as intended.
This article will cover common pitfalls around quoting and filename handling in find -exec. It will help you understand how find parses arguments, when to quote -exec arguments, and how to safely pass filenames to commands.
Understanding Argument Parsing in find
To use -exec correctly, you first need to understand how find parses arguments. The find command splits arguments on whitespace by default. So an unquoted argument like -exec cmd {} +
gets parsed as 3 separate words.
This causes issues if your command or filenames contain spaces or other whitespace. For example, file name with spaces.txt
would get parsed as multiple separate words. So arguments with spaces need quoting to be parsed properly.
When Arguments Get Parsed
Find evaluates arguments at different times depending on the argument:
- Search path and criteria – Evaluated at start to build file list
- -exec arguments – Evaluated as each result file is found
This means you can use {} to substitute file names into -exec arguments. But it also means those arguments need proper quoting for each file.
Escape Characters
Find allows escaping certain characters using the backslash (\). Some common escape sequences are:
- \ – Literal backslash
- \’ – Single quote
- \” – Double quote
- \{ – Literal brace
- \} – Literal brace
Escaping is necessary when matching file names that contain punctuation characters that would otherwise be interpreted by find.
When to Quote Arguments in -exec
Quoting is necessary for -exec arguments in certain cases to avoid errors:
- Commands or scripts with spaces – The entire command should be quoted:
-exec "<cmd> {}" \;
- Passing arguments with spaces – Individual arguments need quotes:
-exec <cmd> "{}" "{}_old" \;
- Wildcards in file names – Quote the {} placeholder to escape wildcards:
-exec <cmd> "{}" \;
On the other hand, quotes are not required if a command or file name does not contain spaces, wildcards or other special characters.
When to Use Single vs Double Quotes
Single quotes (”) prevent any further interpretation inside them. Double quotes (“”) still allow variable and wildcard expansion.
So for literal strings without variables/wildcards, prefer single quotes. But double quotes are useful when you want the shell to process wildcards or variables inside the quoted string.
Escaping Special Characters in Filenames
File names often contain special characters like spaces, punctuation, and wildcards. To handle files correctly, special characters need escaping with backslashes (\) when passing them to -exec.
Spaces
Spaces can be escaped by quoting or preceding with a backslash:
- “file name” – Double quotes
- ‘file name’ – Single quotes
- file\ name – Backslash
Wildcards
Wildcards like * and ? also have special meaning and need escaping:
- “*” – Quote to escape * literal
- \* – Backslash to escape * literal
Other Punctuation
Other problematic punctuation like # $ ; & | > < etc. also need escaping:
- “file#1” – Double quotes
- ‘file#1’ – Single quotes
- file\#1 – Backslash escape
Handling Spaces and Special Chars in Filenames
When find passes file names to a command in -exec, there are a few different ways you can handle spaces and special characters:
Quoting
Enclosing the {} placeholder in quotes handles spaces, wildcards, and other special characters:
find . -exec cmd "{}" \;
Null Byte Separated Format
The -print0 option outputs file names separated by null bytes which allows safely handling all characters:
find . -print0 | xargs -0 cmd
Escape Sequences
Backslash escaping special characters also handles difficult file names:
find . -exec cmd {} \;
But this method is tedious and error prone. Quoting or null bytes are better alternatives.
Passing Filenames Safely to -exec Programs
To recap, here are some best practices for handling file names in -exec:
- Use quotes around the {} placeholder
- Escape spaces, wildcards, and punctuation with backslashes
- Use -print0 | xargs -0 to separate with null bytes
- Don’t heavily nest quotes as this gets confusing
Careful attention to quoting and escaping ensures commands will work correctly even with tricky filenames.
Examples and Best Practices
Quoting Literal Strings
Use single quotes around literal strings without variables and wildcards:
find . -exec 'echo "literal {}"' \;
Escaping spaces and wildcards
Quote the {} placeholder and escape special characters:
find . -name '*1?.txt' -exec cp "{}" "{}_backup" \;
Calling scripts and passing filenames
Quote the script name and {} to handle spaces properly:
find . -iname "*.cfg" -exec './parse config {}' \;