Si un shell est invité à exécuter une commande probablement inutile ( ou partiellement inutile ) connue pour se terminer, comme cat hugeregularfile.txt > /dev/null
, peut-il ignorer l'exécution de cette commande ( ou exécuter un équivalent moins cher, par exemple touch -a hugeregularfile.txt
)?
Plus généralement, le shell est-il similaire aux compilateurs C en ce sens qu'il peut effectuer n'importe quelle transformation sur le code source, tant que le comportement observable de l'extérieur est comme si la machine abstraite l'évaluait?
MODIFIER
Nota Bene: Ma question telle que posée à l'origine avait un titre qui demandait si le shell est autorisé à faire ces optimisations, pas s'il le devrait ou même si des implémentations qui peuvent les faire existent. Je m'intéresse plus à la théorie qu'à la pratique, bien que les deux soient les bienvenus.
cat
ting fait une grande différence. Le shell peut apprendre que le fichier est un périphérique, mais il n'est pas nécessaire qu'il soit fiable.wc
, par exemple). Mais à ma connaissance, POSIX ne prend pas position sur l'optimisation du shell; Ou alors?ksh
. Comme ils ne disent pas un processus séparé mais un environnement de sous-shell pour permettre des optimisations d'économie de fourche.Réponses:
Non, ce serait une mauvaise idée.
cat hugeregularfile.txt > /dev/null
ettouch -a hugeregularfile.txt
ne sont pas les mêmes.cat
va lire tout le fichier, même si vous redirigez la sortie vers/dev/null
. Et la lecture de tout le fichier pourrait être exactement ce que vous voulez. Par exemple, afin de le mettre en cache afin que les lectures ultérieures soient nettement plus rapides. La coquille ne peut pas connaître votre intention.De même, un compilateur C n'optimisera jamais la lecture d'un fichier, même si vous ne regardez pas ce que vous lisez.
la source
true
etfalse
) a des effets secondaires potentiels, et les effets secondaires sont presque toujours le point d'invoquer la commande. Le shell ne pouvait pas connaître ces effets secondaires à l'avance (pour des programmes externes commecat
) sans résoudre le problème de l'arrêt. Donc, à juste titre, il n'essaie pas et suppose que vous pensiez ce que vous avez dit.cat
. En fait, celacat
pourrait faire n'importe quoi, du formatage de votre disque dur au téléchargement d'Internet.true
etfalse
réglé$?
.cat
et/dev/null
ont des significations typiques , mais ils ne sont pas garantis à se comporter de cette façon. Pour effectuer des optimisations tout en ne garantissant aucune modification du comportement attendu, l'optimisation ne pouvait être autorisée que par des constructions implémentées dans le shell lui-même et non par des éléments trouvés dans l'environnement d'exécution ... quelle que soit l'intuition de leurs noms.Non, car ce
/dev/null
n'est qu'un nom, qui pourrait être utilisé pour tout autre périphérique ou pour un fichier autre que ce qui est "normalement" un récepteur de données.Un shell (ou tout autre programme) n'a donc aucune idée, sur la base de son nom, si le fichier dans lequel il écrit fait quelque chose "pour de vrai" avec les données. Il n'y a pas non plus d'AFAIK d'appels système que le programme shell puisse faire, pour déterminer par exemple que le descripteur de fichier ne fait rien.
Votre comparaison avec l'optimisation du code absent dans un programme C ne fonctionne pas, car un shell n'a pas la vue d'ensemble d'un compilateur C sur un morceau de code source. Un shell n'en sait pas assez
/dev/null
pour optimiser votre exemple, plus comme un compilateur C n'en sait pas assez sur le code dans un appel de fonction auquel il est lié dynamiquement, pour ne pas faire l'appel.la source
/dev/null
spécialement, parfois. Un builtin dont la sortie standard est dirigée vers/dev/null
, par exempleecho foo >/dev/null
, n'entraînera aucune écriture/dev/null
. Il ne fait rien de spécial s'il appelle une commande non intégrée (telle quecat file >/dev/null
).cat
pourrait aussi être autre chose. Rien d'autre en fait./dev/null
est l' un des très rares chemins standardisés , ainsi que/dev/tty
,/dev/console
,/tmp
,/dev/
et/
.cat
est en fait un module intégré ksh93 (non activé sauf si vous l'avez mis/opt/ast/bin
avant/bin
(ou partout où il encat
existe)$PATH
). Et oui, maiscat file > /dev/null
avec cette fonction interne neread
le contenufile
, il ne pas écrire sur / dev / null (si elle ouvre et fstats elle).Il n'optimisera pas les commandes en cours d'exécution (et vous avez déjà reçu un certain nombre de bonnes réponses vous expliquant pourquoi cela ne devrait pas l'être), mais il peut optimiser les fourches, les tuyaux / paires de douilles, les lectures dans certains cas. Le type d'optimisations qu'il peut faire:
trap
s ont été définis. Par exemple , danssh -c ls
, la plupart dessh
mises en œuvre (bash
,mksh
,ksh
,zsh
,yash
, certaines versionsash
) ne bifurque pas un processus à termels
.ksh93
, la substitution de commandes ne créera pas de pipe ou de fork un processus jusqu'à ce qu'une commande externe soit appelée ($(echo foo)
par exemple sera étendue àfoo
sans pipe / socketpair ou fork).read
de certains shells (bash
, AT&Tksh
) ne fera pas de lectures sur un octet s'ils détectent que stdin est recherchable (auquel cas ils effectueront des lectures importantes et rechercheront jusqu'à la fin de ce qu'ils sont censés lire).la source
ksh93
est le shell ouvrant la voie sur le front de l' optimisation car son objectif est / devait être considéré comme étant à égalité avec les langages de programmation commeperl
. Vous pouvez donc consulter laksh
documentation, le code (bonne chance) et la liste de diffusion pour plus d'informations.sh -c 'ps -p "$$"'
qui vous donneraps
et nonsh
avec cessh
implémentations, ou avec strace / truss / tusc ...ksh -c 'ps; ps'
et bash -c 'ps; ps' est intéressante. Ksh93 va plus loin dans son optimisation.ksh
nous parlons ici.mksh
se comporte commebash
. Ce comportement est principalement destiné à optimiser des choses commesystem("some command")
. Notez qu'il y a un effet secondaire de cette optimisation en ce qui concerne l'état de sortie des processus terminés par un signal (dans certains shells).ksh93
utilisé pour avoir un bug en ce sens qu'il faisait l'optimisation même lorsque les pièges ont été définis.En voyant
cat hugeregularfile.txt > /dev/null
, le shell n'est pas autorisé à croire que l'action est inutile -cat
ne fait pas partie du shell et pourrait tout faire en théorie et en pratique.Par exemple, l'utilisateur peut avoir renommé le fichier exécutable
rm
àcat
, et tout à coup la ligne effectue un comportement observable de l' extérieur, à savoir la suppression du fichier.L'utilisateur peut en avoir compilé une version
cat
qui va dans une boucle infinie, donc le shell ne peut pas supposer qu'il est «connu pour se terminer» comme vous le suggérez.Quelqu'un peut avoir installé une version
cat
qui fonctionne comme prévu, mais avec un effet secondaire supplémentaire de l'installation d'un rootkit s'il est jamais exécuté avec les privilèges adéquats - encore une fois, le shell devrait l'exécuter correctement.la source
mksh
fait, optimise en faitV=$(cat file)
en en faisant un intégré. Ainsi, le shell peut l'optimiser, mais pas le transformer en un simpletouch -a
.cat
est un module intégrémksh
, mais ce module recourt à l'cat
option du système s'il est passé, c'est pourquoi avec GNUcat
,mksh -c 'cat /dev/null --help'
ne donne pas le même résultat quebash -c 'cat /dev/null --help'
, maismksh -c 'cat --help /dev/null'
vous donne le même quebash -c 'cat --help /dev/null'
(carmksh
cat builtin analyse les options du POSIX manière, tandis que GNU cat les analyse de la manière GNU).V=$(cat file)
peut être optimisé avecV=$(< file)
. Cela accélère les choses même sans intégrécat
.