Pourquoi «ls» nécessite-t-il un processus distinct pour l'exécution?

14

Pourquoi lsnécessite- t-il un processus distinct pour son exécution? Je connais la raison pour laquelle des commandes comme cdne peuvent pas être exécutées par le mécanisme de forking mais y a-t-il un mal si elles lssont exécutées sans forking?

crisron
la source
1
Bien qu'il s'agisse d' lsun programme externe echo *ou echo * .*(selon les options du shell), il répertorie les fichiers sans bifurquer.
gerrit
C'est encore mieux: printf "% s \ n" *
Costa
Remarque sur la diversité du shell: tcsh a une fonction intégrée ls-Fqui agit comme ls -F. C'est là pour l'efficacité. Vous obtenez toujours -Fce qui est généralement une bonne idée. Si vous spécifiez toute autre option, elle renvoie à la commande externe.

Réponses:

18

La réponse est plus ou moins lsun exécutable externe. Vous pouvez voir son emplacement en exécutant type -p ls.

Pourquoi n'est-il pas lsintégré au shell, alors? Eh bien, pourquoi devrait-il en être ainsi? Le travail d'un shell n'est pas d'englober toutes les commandes disponibles, mais de fournir un environnement capable de les exécuter. Certains shells modernes ont echo, printfet leurs semblables en tant que builtins, qui ne doivent pas être techniquement intégrés, mais qui le sont pour des raisons de performances lorsqu'ils sont exécutés de manière répétée (principalement en boucles serrées). Sans les rendre intégrés, le shell devrait bifurquer et exécuter un nouveau processus pour chaque appel, ce qui pourrait être extrêmement lent.

À tout le moins, l'exécution ls, un exécutable externe, nécessite l'exécution d'une des exécutions système de la famille exec. Vous pouvez le faire sans bifurquer, mais cela remplacerait le shell principal que vous utilisez. Vous pouvez voir ce qui se passe dans cette instance en procédant comme suit:

exec ls; echo "this never gets printed"

Puisque l'image de processus de votre shell est remplacée, le shell actuel n'est plus accessible après cela. Pour que le shell puisse continuer à s'exécuter après avoir exécuté ls, la commande doit être intégrée au shell.

Le fork permet de remplacer un processus qui n'est pas votre shell principal, ce qui signifie que vous pouvez continuer à exécuter votre shell par la suite.

Chris Down
la source
1
Je pense qu'il demande pourquoi ls (1) n'est pas une fonction intégrée des shells, dont quelqu'un aurait besoin pour expliquer comment différents fournisseurs ont différentes options pour ls (1) et capables d'interroger différentes choses à partir du système de fichiers, etc. Et aussi les hauts et les bas de l'avoir «intégré» à la coque.
llua
@llua J'ai ajouté quelques informations à ce sujet, et les cas d'exception de echo, printf, etc.
Chris Bas
Il n'est pas toujours clair pourquoi certaines choses sont intégrées et d'autres non. Par exemple, pourquoi n'est-il cdpas un exécutable externe?
Faheem Mitha
@FaheemMitha Il existe un cdexécutable externe dans les systèmes d'exploitation compatibles POSIX ( voir ici ). Si vous voulez réellement chdir () dans le processus en cours, cependant, vous devez l'intégrer dans le shell.
Chris Down du
il est devenu une habitude pourquoi lsexterne, mais il peut également être implémenté dans un shell. Voir busybox.
15

Le manuel de référence Bash déclare:

Les commandes intégrées sont nécessaires pour implémenter des fonctionnalités impossibles ou peu pratiques à obtenir avec des utilitaires distincts.

Autrement dit, les shells sont conçus pour inclure uniquement des commandes intégrées si:

  1. Requis par la norme POSIX
  2. Commandes qui nécessitent un accès au shell lui-même, telles que les commandes intégrées au contrôle des travaux
  3. Les commandes qui sont très simples, ne dépendent pas du système d'exploitation et augmentent l'efficacité d'exécution lorsqu'elles sont implémentées en tant que intégrées, telles que printf

La lscommande ne correspond à aucune des exigences ci-dessus.

Cependant , il n'y a aucune contrainte de programmation qui empêcherait d' lsêtre implémentée en tant que intégré, c'est-à-dire s'exécutant dans le même processus que l'interpréteur bash. Les raisons de conception pour lesquelles les commandes ne sont pas implémentées en tant que composants intégrés du shell sont les suivantes:

  1. Le shell doit être séparé du système de fichiers - aucune commande intégrée ne doit dépendre du bon fonctionnement d'un système de fichiers ou de périphériques
  2. Une commande qui pourrait être de type système de fichiers ou dépendante du système d'exploitation devrait être un exécutable distinct
  3. Une commande à laquelle vous souhaiterez peut-être diriger vers ou depuis devrait être un processus distinct
  4. Une commande que vous voudrez peut-être exécuter en arrière-plan devrait être un exécutable distinct
  5. Une commande qui a un grand nombre de paramètres possibles est mieux implémentée dans un exécutable séparé
  6. Les commandes qui devraient avoir la même sortie, quel que soit le type de shell (bash, csh, tsh, ...) les invoquant doivent être des exécutables autonomes

Concernant la première raison - Vous voulez que le shell soit aussi indépendant et résilient que possible. Vous ne voulez pas que le shell lsreste bloqué sur un montage NFS qui "ne répond toujours pas".

Concernant la deuxième raison - Dans de nombreux cas, vous souhaiterez peut-être utiliser un shell pour un système qui utilise Busybox ou un autre système de fichiers qui a une lsimplémentation différente . Ou même utiliser la même source de shell dans les systèmes d'exploitation qui ont différentes lsimplémentations.

Concernant la troisième raison - Pour une expression telle que find . -type d | xargs ls -ladcelle-ci il serait difficile voire impossible de l'implémenter lsdans le même processus que l'interpréteur shell.

Concernant la quatrième raison - Certaines lscommandes peuvent prendre beaucoup de temps. Vous voudrez peut-être que le shell continue de faire autre chose en attendant.


Remarque: Voir ce message utile de Warren Young en réponse à une question similaire.

Jonathan Ben-Avraham
la source
Vous avez manqué la facilité de canaliser la sortie si c'est une commande séparée, et toute la programmation qu'il faudrait pour diriger une primitive shell dans un exécutable séparé.
Bruce Ediger
@BruceEdiger: Quel plaisir de recevoir un commentaire de l'estime BE. Merci! Je crois que la raison 3 couvre votre commentaire, non?
Jonathan Ben-Avraham
1
Je pensais davantage à la façon dont le code source du shell lui-même serait compliqué s'il devait gérer des tuyaux pour des processus externes et diriger la sortie d'une commande interne comme l'hypothétique lsdans un processus externe. Cela pourrait être fait, mais ce serait compliqué.
Bruce Ediger
1
Je crains que la plupart sinon la totalité de vos 5 points soient sans objet. 1: ls est (espérons-le) indépendant de l'implémentation du système de fichiers. C'est au noyau de fournir une interface cohérente à la bibliothèque et aux applications standard. 2: ls est probablement moins dépendant du système d'exploitation que le shell. 3: les obus permettent définitivement des intégrations dans les pipelines. 4: les shells permettent définitivement d'exécuter les buildins en arrière-plan. 5: c'est assez subjectif.
jlliagre
1
@ JonathanBen-Avraham @BruceEdiger Les coques ne gèrent-elles pas déjà le boîtier des tuyaux pour les modules intégrés avec des sous-coques? par exemple bashsortie alias | grep ls. entréecat /etc/passwd | while read a; do echo "$a"; done
Matt
2

lsne nécessite pas de processus séparé. Très peu de commandes nécessitent en fait un processus distinct: seules celles qui doivent changer de privilèges.

En règle générale, les shells implémentent des commandes en tant que commandes intégrées uniquement lorsque ces commandes doivent être implémentées en tant que commandes intégrées. Les commandes comme alias, cd, exit, export, jobs, ... besoin de lire ou de modifier un état interne de la coque, et ne peut donc pas être des programmes distincts. Les commandes qui n'ont pas de telles exigences peuvent être des commandes distinctes; de cette façon, ils peuvent être appelés à partir de n'importe quel shell ou autre programme.

En regardant la liste des commandes intégrées dans bash, seules les commandes intégrées suivantes peuvent être implémentées en tant que commandes distinctes. Pour certains d'entre eux, il y aurait une légère perte de fonctionnalité.

  • command- mais il perdrait son utilité dans des situations où il se PATHpeut qu'il ne soit pas configuré correctement et que le script l'utilise commanddans le cadre de sa configuration.
  • echo - c'est une fonction intégrée pour l'efficacité.
  • help - il pourrait utiliser une base de données distincte, mais l'incorporation du texte d'aide dans l'exécutable du shell a l'avantage de rendre l'exécutable du shell autonome.
  • kill - il y a deux avantages à avoir une fonction intégrée: elle peut reconnaître les désignations de tâches en plus des ID de processus, et elle peut être utilisée même lorsqu'il n'y a pas suffisamment de ressources pour démarrer un processus séparé.
  • printf- pour la même raison que echo, et aussi pour supporter l' -voption de mettre la sortie dans une variable.
  • pwd - la fonction intégrée offre la possibilité supplémentaire de suivre le répertoire courant logique (en laissant intacts les liens symboliques au lieu de les étendre).
  • test- c'est une fonction intégrée pour l'efficacité (et bash fait aussi de la magie avec les fichiers appelés /dev/fd/…sur certains systèmes d'exploitation).

Quelques obus offrent un nombre important de modules complémentaires supplémentaires. Il y a le châssis , qui est un shell conçu pour être un binaire autonome pour les réparations d'urgence (lorsque certaines commandes externes peuvent ne pas être utilisables). Il a un intégré ls, appelé -ls, ainsi que d'autres outils tels que -grepet -tar. Les fonctions intégrées de Sash ont moins de capacités que les commandes à part entière. Zsh propose des fonctionnalités similaires dans son module zsh / files . Il n'en a pas ls, mais une extension générique ( echo *) et zstatpeut servir une fonction similaire.

Gilles 'SO- arrête d'être méchant'
la source
2

Je pense que quelque chose que les gens manquent ici est la complexité de cisaillement du lsprogramme GNU sur Linux. La comparaison de la taille de l' exécutable de lsla bashet des dashobus sur mon système Debian, nous voyons qu'il est assez grand:

graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30  2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls

Inclure une version lsaussi complète que la version GNU bashaugmenterait la taille de l'exécutable de 10%. C'est presque la même taille que la dashcoque complète !

La plupart des commandes internes du shell sont choisies parce qu'elles s'intègrent avec le shell d'une manière que les exécutables externes ne peuvent pas (la question souligne cd, mais un autre exemple est la version bash de l' killintégration avec le contrôle des tâches bash) ou parce que ce sont des commandes très simples à implémenter, donnant une grande vitesse vs gain de taille ( trueet falsesont à peu près aussi simples que possible).

GNU lsa eu un long cycle de développement et implémente plusieurs options pour personnaliser les résultats affichés. L'utilisation d'un ls intégré par défaut entraînerait la perte de cette fonctionnalité ou augmenterait considérablement la complexité et la taille du shell.

Graeme
la source
1

cdest intégré au shell, lsest un programme séparé que vous verrez sur /bin/ls.

DopeGhoti
la source
0

Faites ce que vous cherchez:

printf "%s\n" *

Vous pouvez également stocker les noms de fichiers dans un tableau:

files=(`printf "%s\n" *`)  #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done

Mais il ne se soucie pas des espaces dans les noms
Cela passe à variable et se soucie des espaces:

printf "%s\n" * | while read a; do echo $a; done
Costa
la source