2

I'd like to use find inside a command substitution, where the returned filenames contain whitespace. What option do I need so it correctly quotes the filenames? I tried -print0, but it will not work in the shell itself.

example:

command $(find . -type f) some other params

I also tried with -exec echo "{}" \;, but that was of no help either.


If I use set -x to display shell expansion and the actual command which is executed I get:

$ command `find -type f -printf \"%p\"\ ` some other params
++ find -type f -printf '"%p" '
+ command '"./file_with' 'blanks"' '"./another' 'file"' some other params

Where are the single quotation marks coming from and why are they applied to each "word"?

knittl
  • 246,190
  • 53
  • 318
  • 364
  • do you know about xargs? `find . -type f -print0 | xargs -0 yourCmd opts`? xargs will 'feed' N number of output from find to `yourCmd` and keep repeating until all output is done. Xargs is the prefered way to pass find output to a command in GnuLinux land (not so much in old Unix Solaris/HP/etc). There may be something about `yourCmd` that prevents this from working, but above is the place to start. Good luck. – shellter Feb 09 '12 at 15:42
  • I know `xargs` (should have mentioned in the question), but the command should only be executed once, not once for each input file. I need the complete file list passed to the command in a single step. (tried `-L` and `-n` from xargs) – knittl Feb 09 '12 at 15:45
  • my point about 'xargs will feed N number of output' means that xargs will stage yourCmd with as many arguments as can fit on one execution of the command line AND only rexecute yourCmd if needed (and as many times as needed). right? If you need to process 100000 files, no use of `yourCmd $(find . -type f )` will work, you'll get a msg like 'too many filenames' Xargs is meant to help solve that sort of problem by executing yourCmd as few as times as possible. Given a list of 10 files through xargs, yourCmd will run only 1 time, not 10 x. Good luck. – shellter Feb 09 '12 at 16:16
  • @shellter: I know, but my command is still executed several times, I only have a bunch (like 20) of files. Tried `-L`/`-n` to no avail. – knittl Feb 09 '12 at 16:21
  • I don't know what `-L / -n` does **and I don't think you need them in this case**, but unless the path/filename generated by find command are strings that are 1000 chars and longer, I don't see how 20 filenames could blow this up. Can you edit your question to show the first line or two of output from `find . -type f -print0`? Good luck. – shellter Feb 09 '12 at 16:42
  • They set the maximum number of arguments that are passed to the command. I set them both to 100, because the standard values executed the command as many times as there were files. All files together are 1178 bytes/chars – knittl Feb 09 '12 at 16:46

3 Answers3

3

Put the find result in an array, and run command "${array[@]}" some other params.

Community
  • 1
  • 1
l0b0
  • 55,365
  • 30
  • 138
  • 223
  • `command "${array[@]}" some other params` finally did the trick for me. But boy, this is more than complicated … – knittl Feb 09 '12 at 16:12
  • Unfortunately Bash is one language where whitespace is extremely complicated, if you want to handle it correctly in all cases. – l0b0 Feb 09 '12 at 16:14
0

Maybe the printf action is more amenable to being contained in a substitution (GNU find only, though):

command $(find . -type f -printf \"%P\"\ ) some other params

The %P placeholder is the filename minus the argument to find, so in cases other than find ., you'd probably want %p instead.

John Flatness
  • 32,469
  • 5
  • 79
  • 81
-2
find /what/ever -name "what ever" -exec echo "\{\}" \;

works here (Ubuntu 10.04 default gterm with bash)

Just tried

find /bin -name ls -exec \{\} -lah \;
`find /bin -name ls -exec echo \{\} \;` -lah
MYCMD=`find /bin -name ls -exec echo \{\} \;` && $MYCMD -lah
MYCMD=$(`find /bin -name ls -exec echo \{\} \;` -lah)  && echo $MYCMD
MYCMD=$(`find /bin -name ls` -lah)  && echo $MYCMD

all work as expected

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92