First to cut off trivial but inapplicable answers: I can use neither the
xargs trick nor its variants (like
-exec) because I need to use few such expressions per call. I will get back to this at the end.
Now for a better example let's consider:
$ find -L some/dir -name \*.abc | sort some/dir/1.abc some/dir/2.abc some/dir/a space.abc
How do I pass those as arguments to
Just doing it doesn't do the trick
$ ./program $(find -L some/dir -name \*.abc | sort)
program gets following arguments:
: ./program : some/dir/1.abc : some/dir/2.abc : some/dir/a : space.abc
As can be seen, the path with space was split and
program considers it to be two different arguments.
Quote until it works
It seems novice users such as myself, when faced with such problems, tend to randomly add quotes until it finally works - only here it doesn't seem to help…
$ ./program "$(find -L some/dir -name \*.abc | sort)" : ./program : some/dir/1.abc some/dir/2.abc some/dir/a space.abc
Because the quotes prevent word-splitting, all the files are passed as a single argument.
Quoting individual paths
A promising approach:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort) : "some/dir/1.abc" : "some/dir/2.abc" : "some/dir/a : space.abc"
The quotes are there, sure. But they are no longer interpreted. They are just part of the strings. So not only they did not prevent word splitting, but also they got into arguments!
Then I tried playing around with
IFS. I would prefer
-z anyway - so that they will have no issues on "wired paths" themselves. So why not force word splitting on the
null character and have it all?
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z) : ./program : some/dir/1.abcsome/dir/2.abcsome/dir/a : space.abc
So it still splits on space and does not split on the
I tried to place the
IFS assignment both in
$(…) (as shown above) and before
./program. Also I tried other syntax like
\x00 both quoted with
" as well as with and without the
$. None of those seemed to make any difference…
And here I'm out of ideas. I tried few more things but all seemed to run down to the same problems as listed.
What else could I do? Is it doable at all?
Sure, I could make the
program accept the patterns and do searches itself. But it is a lot of double work while fixing it to a specific syntax. (What about providing files by a
grep for example?).
Also I could make the
program accept a file with a list of paths. Then I can easily dump
find expression to some temp file and provide the path to that file only. This could supported be along direct paths so that if user has just a simple path it can be provided without intermediate file. But this doesn't seem nice - one needs to create extra files and take care of them, not to mention extra implementation required. (On the plus side, however, it could be a rescue for cases in which the number of files as arguments start to cause issues with command line length…)
At the end, let me remind you again that
xargs (and alike) tricks will not work in my case. For description simplicity I'm showing only one argument. But my true case looks more like this:
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort) $ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort) $ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
So doing an
xargs from one search still leaves me with how to deal with the other one…