D'abord pour couper les réponses triviales mais inapplicables: je ne peux utiliser ni l' astuce find
+ xargs
ni ses variantes (comme find
avec -exec
) car j'ai besoin d'utiliser peu de telles expressions par appel. J'y reviendrai à la fin.
Maintenant, pour un meilleur exemple, considérons:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Comment puis-je transmettre ces arguments à program
?
Le faire ne fait pas l'affaire
$ ./program $(find -L some/dir -name \*.abc | sort)
échoue car program
obtient les arguments suivants:
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
Comme on peut le voir, le chemin avec l'espace a été divisé et program
considère qu'il s'agit de deux arguments différents.
Citez jusqu'à ce que cela fonctionne
Il semble que les utilisateurs novices comme moi, lorsqu'ils sont confrontés à de tels problèmes, ont tendance à ajouter des citations au hasard jusqu'à ce que cela fonctionne enfin - seulement ici, cela ne semble pas aider ...
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Étant donné que les guillemets empêchent la séparation des mots, tous les fichiers sont transmis en tant qu'argument unique.
Citation de chemins individuels
Une approche prometteuse:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
Les citations sont là, bien sûr. Mais ils ne sont plus interprétés. Ils ne sont qu'une partie des chaînes. Ainsi, non seulement ils n'ont pas empêché le fractionnement de mots, mais ils se sont aussi mis à discuter!
Changer IFS
Ensuite, j'ai essayé de jouer avec IFS
. Je préférerais find
avec -print0
et sort
avec de -z
toute façon - afin qu'ils n'aient aucun problème sur les "chemins câblés" eux-mêmes. Alors pourquoi ne pas forcer le mot à se scinder sur le null
personnage et tout avoir?
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
Donc, il se divise toujours sur l'espace et ne se divise pas sur le null
.
J'ai essayé de placer l' IFS
affectation à la fois $(…)
(comme indiqué ci-dessus) et avant ./program
. Aussi j'essayé d' autres syntaxe comme \0
, \x0
, à la \x00
fois cité avec '
et "
ainsi qu'avec et sans $
. Rien de tout cela ne semblait faire de différence…
Et là, je suis à court d'idées. J'ai essayé quelques autres choses, mais tout semblait se résumer aux mêmes problèmes que ceux énumérés.
Que pouvais-je faire d'autre? Est-ce faisable du tout?
Bien sûr, je pourrais faire program
accepter les modèles et faire des recherches lui-même. Mais c'est beaucoup de travail double tout en le fixant à une syntaxe spécifique. (Qu'en est-il de la fourniture de fichiers par un grep
par exemple?).
Je pourrais aussi faire program
accepter un fichier avec une liste de chemins. Ensuite, je peux facilement vider l' find
expression dans un fichier temporaire et fournir le chemin d'accès à ce fichier uniquement. Cela pourrait être pris en charge le long de chemins directs de sorte que si l'utilisateur a juste un chemin simple, il peut être fourni sans fichier intermédiaire. Mais cela ne semble pas agréable - il faut créer des fichiers supplémentaires et en prendre soin, sans parler de l'implémentation supplémentaire requise. (Du côté positif, cependant, cela pourrait être un sauvetage pour les cas où le nombre de fichiers en tant qu'arguments commence à causer des problèmes avec la longueur de la ligne de commande…)
À la fin, permettez-moi de vous rappeler à nouveau que les astuces find
+ xargs
(et similaires) ne fonctionneront pas dans mon cas. Pour simplifier la description, je ne montre qu'un seul argument. Mais mon vrai cas ressemble plus à ceci:
$ 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
Donc, faire une xargs
recherche à partir d'une recherche me laisse encore comment gérer l'autre…
mapfile
(ou son synonymereadarray
). Mais, il fonctionne!