Supposons qu'un répertoire contient 100 fichiers commençant par la lettre «a».
Si je fais un grep <some string> a*
depuis le terminal, comment le shell va-t-il gérer cela?
Va-t-il développer l'expression régulière, obtenir une liste de tous les fichiers commençant par a et grep sur chacun de ceux-ci de manière séquentielle? Ou existe-t-il un autre moyen?
Supposons que j'ai un tableau des noms de fichiers ci-dessus qui commencent par «a». Cela prendra-t-il plus / moins de temps si j'écris une boucle for et fais l'itération moi-même dans un script shell ou un programme ac?
glob
pas une expression régulière. Grande différence.Réponses:
Tout d'abord, un nitpick: une chaîne comme
a*
dans la syntaxe shell normale est un glob, qui fonctionne différemment des expressions régulières.Sur une vue d'ensemble de haut niveau, l'interpréteur de shell (c'est-à-dire bash) développe la chaîne
a*
en une liste de chaque nom de fichier correspondant au modèlea*
. Celles-ci font alors partie des paramètres de ligne de commande d'une seule instance degrep
(pour les programmeurs, tous les mots développés vont comme des chaînes distinctes dans l'argv
argument demain
). Cettegrep
commande unique analyse ensuite les arguments de la manière qu'elle choisit, et c'estgrep
à interpréter ces arguments comme des noms de fichiers, des options, des arguments d'options, des expressions régulières, etc., et de prendre les actions appropriées. Tout se passe séquentiellement (aucunegrep
implémentation AFAIK n'utilise plusieurs threads).Si vous implémentez une boucle dans un script shell pour faire la même chose, il est presque garanti d'être plus lent que le processus ci-dessus, pour les raisons suivantes. Si vous générez un nouveau processus grep pour chaque fichier, il sera très certainement plus lent en raison de la multiplication inutile des frais généraux de création de processus. Si vous avez construit vous-même la liste des arguments dans le script shell et utilisé une seule instance de
grep
, tout ce que vous faites dans le shell sera encore plus lent car les commandes shell doivent être interprétées (par bash), ce qui ajoute une couche supplémentaire de code, et vous aurez juste réimplémenter ce que bash faisait déjà plus rapidement en interne dans le code compilé.Quant à l'écrire vous-même en C, vous pouvez probablement facilement obtenir des performances comparables au processus décrit dans le premier paragraphe, mais il est peu probable que vous puissiez obtenir un gain de performances suffisant par rapport aux implémentations grep / bash actuelles pour justifier le temps dépensé sans plonger dans les optimisations de performances spécifiques à la machine ou sacrifier la portabilité. Vous pourriez peut-être essayer de proposer une version arbitrairement parallélisable de
grep
, mais même cela peut ne pas aider car vous êtes plus susceptible d'être lié aux E / S que lié au CPU. L'expansion des globes et grep sont déjà "assez rapides" pour la plupart des utilisations "normales".la source
zcat
etzgrep
; pas besoin de les décompresser un par unOui, il se développera en une liste de fichiers et transmettra la liste résultante au
grep
programme. C'est du moins ce qui estman bash
dit dans la sous-section Expansion du nom de chemin .Il existe une autre façon d'utiliser l'expansion dans des cas simples comme vous le mentionnez: écrivez
grep <some_string> a
et avant d'appuyer sur*
, appuyez sur ESC. Cela étendra la liste des fichiers correspondants directement dans la ligne de commande, afin que vous puissiez vérifier que la liste est correcte avant d'appuyer sur Enter.Quant à la deuxième partie de votre question, cela dépend. Si vous voulez écrire une boucle for qui exécute tour à tour grep sur chacun des fichiers, alors ce serait certainement plus lent, car le programme grep ne sera pas exécuté une fois, mais une fois par fichier. Cependant, il est important de garder à l'esprit qu'il existe une certaine limite à la longueur étendue des arguments de ligne de commande que vous pouvez utiliser, bien qu'elle soit généralement assez élevée. Pour voir cela, vous pouvez essayer
grep adasdsadf /usr/*/*/* >/dev/null
.la source
ESC+*
n'est pas exactement la même chose que de laisser bash se développer * carESC+*
il insérera des fichiers dot (noms commençant par a.
) alors que l'expansion de*
dépend dudotglob
shopt
paramètre. La séquence de touches pour développer et insérer des globes estC-x *
par défaut et correspond à la commande readlineglob-expand-word
.a*
expansion, mais est certainement important à plus grande échelle.zsh
Remarque: il suffit de frapper la touche de tabulation sur les paramètres extensibles (motifs globaux, expansion d'accolade, substitution de commande,…) pour les développer.C-x
raccourci et il n'élargit pas la liste des fichiers sur mon système (en utilisant bash).C-x *
ne fait que des globes qui ne font que des noms de fichiers, maisEsc *
en fait beaucoup plus car c'est le casinsert-completions
, comme dans tous les compléments possibles. Cela signifie que l'utilisationEsc *
sur une ligne de commande vide insérera le nom de chaque fichier exécutable unique dans votre$PATH
, par exemple.