Le shell est-il autorisé à optimiser les commandes de terminaison inutiles?

27

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.

Iwillnotexist Idonotexist
la source
Non, le shell n'est pas aussi intelligent que les compilateurs modernes. En fait, c'est plutôt stupide. Cela n'optimiserait aucun code inutile.
devnull
12
Deviner quelle est l'intention de l'utilisateur n'est pas quelque chose que le shell devrait faire. L'utilisateur pourrait essayer de faire presque n'importe quoi avec cette commande, l'optimiser serait la mauvaise chose à faire, même si c'était possible.
Chris Down
1
Peu importe que si le fichier était un périphérique, le catting 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.
yo '10
3
Les compilateurs @StephaneChazelas C n'ont pas besoin de "demander la permission à quelqu'un" pour optimiser leurs programmes compilés; Il y a un que, si la règle dans la norme C qui leur permet de le faire. La norme POSIX semble avoir normalisé au moins un shell ( pubs.opengroup.org/onlinepubs/009695399/utilities/… ), ainsi que de nombreux autres utilitaires ( pubs.opengroup.org/onlinepubs/009604499/utilities/wc.html pour wc, par exemple). Mais à ma connaissance, POSIX ne prend pas position sur l'optimisation du shell; Ou alors?
Iwillnotexist Idonotexist
2
L'optimisation améliore les performances avec des raccourcis sans affecter la fonctionnalité. Tant que la fonctionnalité est garantie, je ne vois pas d'objection POSIX. Cependant, l' optimisation que vous proposez briserait les spécifications du chat . Il existe des libellés spécifiques dans la spécification POSIX qui sont là pour s'adapter au type d'optimisation effectué par ksh. Comme ils ne disent pas un processus séparé mais un environnement de sous-shell pour permettre des optimisations d'économie de fourche.
Stéphane Chazelas

Réponses:

26

Non, ce serait une mauvaise idée.

cat hugeregularfile.txt > /dev/nullet touch -a hugeregularfile.txtne sont pas les mêmes. catva 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.

scai
la source
2
@Iwillnotexist: Chaque commande utile (sauf sans doute trueet false) 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 comme cat) 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.
cHao
5
@IwillnotexistIdonotexist Non, le shell ne peut pas voir tout ce qui va se passer. Il n'en a aucune idée cat. En fait, cela catpourrait faire n'importe quoi, du formatage de votre disque dur au téléchargement d'Internet.
scai
5
"Unix n'a pas été conçu pour empêcher ses utilisateurs de faire des choses stupides, car cela les empêcherait également de faire des choses intelligentes." - Doug Gwyn
Agi Hammerthief
7
@cHao Et même trueet falseréglé $?.
Kyle Strand
3
Comme @scai indiqué plus haut, executables ne sont pas comme mots clés du langage: catet /dev/nullont 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.
andybuckley
20

Non, car ce /dev/nulln'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/nullpour 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.

Anthon
la source
4
Il s'avère que ksh93 traitera /dev/nullspécialement, parfois. Un builtin dont la sortie standard est dirigée vers /dev/null, par exemple echo 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 que cat file >/dev/null).
Mark Plotnick
En fait, cela catpourrait aussi être autre chose. Rien d'autre en fait.
orion
3
En fait , /dev/nullest l' un des très rares chemins standardisés , ainsi que /dev/tty, /dev/console, /tmp, /dev/et /.
Gilles 'SO- arrête d'être méchant'
2
@MarkPlotnick cat est en fait un module intégré ksh93 (non activé sauf si vous l'avez mis /opt/ast/binavant /bin(ou partout où il en catexiste) $PATH). Et oui, mais cat file > /dev/nullavec cette fonction interne ne readle contenu file, il ne pas écrire sur / dev / null (si elle ouvre et fstats elle).
Stéphane Chazelas
14

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:

  • Avec la plupart des shells modernes, la dernière commande d'un script sera généralement exécutée dans le processus du shell, sauf si certains traps ont été définis. Par exemple , dans sh -c ls, la plupart des shmises en œuvre ( bash, mksh, ksh, zsh, yash, certaines versions ash) ne bifurque pas un processus à terme ls.
  • dans 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 à foosans pipe / socketpair ou fork).
  • L' intégration readde certains shells ( bash, AT&T ksh) 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).
Stéphane Chazelas
la source
J'aime cette réponse, mais on ne sait pas si c'est la raison d'origine, ou si l'information est tirée d'une référence (que j'aimerais approfondir)
yoniLavi
3
@yoniYalovitsky, c'est la raison originale . ksh93est 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 comme perl. Vous pouvez donc consulter la kshdocumentation, le code (bonne chance) et la liste de diffusion pour plus d'informations.
Stéphane Chazelas
1
@HenkLangeveld, oui, vous pouvez vérifier avec sh -c 'ps -p "$$"'qui vous donnera pset non shavec ces shimplémentations, ou avec strace / truss / tusc ...
Stéphane Chazelas
1
La différence entre ksh -c 'ps; ps'et bash -c 'ps; ps' est intéressante. Ksh93 va plus loin dans son optimisation.
Henk Langeveld
1
@HenkLangeveld, dépend de quelle implémentation kshnous parlons ici. mkshse comporte comme bash. Ce comportement est principalement destiné à optimiser des choses comme system("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). ksh93utilisé pour avoir un bug en ce sens qu'il faisait l'optimisation même lorsque les pièges ont été définis.
Stéphane Chazelas
7

En voyant cat hugeregularfile.txt > /dev/null, le shell n'est pas autorisé à croire que l'action est inutile - catne 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 catqui 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 catqui 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.

Peter est
la source
2
En mkshfait, optimise en fait V=$(cat file)en en faisant un intégré. Ainsi, le shell peut l'optimiser, mais pas le transformer en un simple touch -a.
Steve Schnepp
1
@SteveSchnepp, cat est un module intégré mksh, mais ce module recourt à l' catoption du système s'il est passé, c'est pourquoi avec GNU cat, mksh -c 'cat /dev/null --help'ne donne pas le même résultat que bash -c 'cat /dev/null --help', mais mksh -c 'cat --help /dev/null'vous donne le même que bash -c 'cat --help /dev/null'(car mkshcat builtin analyse les options du POSIX manière, tandis que GNU cat les analyse de la manière GNU).
Stéphane Chazelas
Dans bash et ksh93, le V=$(cat file)peut être optimisé avec V=$(< file). Cela accélère les choses même sans intégré cat.
Henk Langeveld