There are many different answers, depending on how exactly you want to use the output, as well as what assumptions you are making about what odd characters aren't in the filenames. The find command doesn't have an option to escape special characters, but if it did, it's choice of what to escape might not match the exact needs of your program. Considering that the only illegal characters in filenames are '/' and NULL, there are a lot of edge cases.
In my case, I wanted to process the file names as elements in an array in Bash, so I wanted something like:
FILES=( $(find . -type f) )
That doesn't work with spaces (or tabs, for that matter). That also kills the newlines from the find command, making them useless as separators. You can set the field separator in Bash to something different. Ideally, you would set it to null and use -print0 in find, but null is not allowed as a field separator in Bash. My solution is to pick a character that we assume is not in any filenames, like 0x01 (ctrl-a), and use that:
IFS=$'\x01'
FILES=( $(find . -type f | sed -e 's/$/\x01/') )
unset IFS
for F in "${FILES[@]}"; do
useful_command "$F"
done
Note the need to unset IFS to restore it to the default. That won't work with filenames with newlines in them, but should work with most other filenames.
If you're really paranoid, then you'll need to do a find piped to hexdump, split out the results to get all the hex values, and look for one that isn't in the results. Then use that value. I'm sure Johnny Drop Tables has files with every hex code in the file names. If you're paranoid, create file and directory names using all 253 legal characters and test. Probably the only solutions that would pass that test would be ones using 'find -print0' piped to xargs or a custom C program.
-exec
flag withfind
? you could potentially alleviate this error and make your command more efficient by doing-exec
instead of piping it to other commands. Just my $.02 – h3rrmiller Jul 01 '13 at 15:56find
formats the file names just fine; they are written one name per line. (Of course, this is ambiguous if a filename contains a newline character.) So the problem is the receiving end "choking" when it gets a space, which means you have to tell us what the receiving end is if you want a meaningful answer. – rici Jul 01 '13 at 16:40find
to offer an option to output file names in a format suitable for the shell. In general, though, the-print0
GNUfind
extension works fine for many other scenarios (too), and you should learn to use it in any event. – tripleee Jul 01 '13 at 16:55read
? -- most shell utilities don't accept filenames throughstdin
, but the ones which do (such asxargs
) do not require quoting. – rici Jul 01 '13 at 18:02ls $(command...)
does not feed the list throughstdin
. It puts the output of$(command...)
directly into the command line. In that case, it is the shell which is reading from the c, and it will use the current value of$IFS
to decide how to wordsplit the output. In general, you're better off usingxargs
. You won't notice a performance hit. – rici Jul 01 '13 at 18:06find
to produce a correctly-formatted string for your program. Fine. So what input format does the program expect? You need to tell us! Separated by newlines and doesn't support newlines in file names? Separated by null bytes? Base-64-encoded on separate lines? … – Gilles 'SO- stop being evil' Jul 01 '13 at 21:52find -printf '"%p"\n'
will add double quotes around each found name, but will not properly quote any double quotes in a file name. If your file names do not have any embedded double quotes, you can ignore the problem: or pipe throughsed 's/"/&&/g;s/^""/"/;s/""$/"/'
. If your file names end up being handled by the shell, you should probably use single quotes instead of double quotes, though (otherwisesweet$HOME
will become something likesheet/home/you
). And this is still not very robust against file names with newlines in them. How do you want to handle those? – tripleee Jul 02 '13 at 09:23