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 {}' \;  

Leave a Reply

Your email address will not be published. Required fields are marked *