Un shell interactif peut-il devenir non interactif ou vice versa?

15

Un shell interactif peut-il devenir non interactif ou vice versa?

Remarque: J'ai fait beaucoup de recherches sur la question fondamentale, "Quelle est la différence entre interactif et non interactif?", Et les résultats de ma recherche m'ont amené à poser cette question.

Cette question a un long préambule en partie parce qu'il est crucial de savoir quel type de définition nous utilisons pour "interactif" afin d'y répondre. Une définition pourrait être une étiquette arbitraire pour un certain ensemble; il pourrait être descriptif de diverses propriétés; ou il peut vous donner des informations que vous pouvez utiliser pour prédire le comportement et comprendre le but. Ce dernier type, nous pouvons l'appeler une "définition d'action" ou une "définition dynamique" et c'est le plus utile.


Dans man 1p sh, la définition suivante d'un shell interactif est donnée:

   If the -i option is present, or  if  there  are  no  operands  and  the
   shells  standard  input and standard error are attached to a terminal,
   the shell is considered to be interactive.

D'après la mention de "l'option -i" et l'utilisation du mot "opérandes", cela fait référence à l' invocation d' un shell , et non à des attributs qui pourraient être examinés dans un shell en cours d'exécution.

La page de manuel de Bash l'exprime un peu différemment:

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.   PS1 is set and $- includes i if bash is interactive, allowing
   a shell script or a startup file to test this state.

La définition de la première phrase ne fait à nouveau référence qu'au démarrage d'un shell.

La deuxième phrase (dans ma lecture) définit les conditions qui sont utilisées comme mandataires pour établir si le shell a été démarré de la manière particulière définie comme le rendant «interactif».

Notez que je n'interprète pas cette phrase comme: "Un shell bash est interactif si et seulement si $-inclut 'i'." $-semble être juste un indicateur pratique, pas une définition de l'interactif. Ceci est d'une importance cruciale pour ma question.


Ces deux shdéfinitions (la définition POSIX et Bash) sont des définitions mécaniques qui indiquent dans quelles circonstances l'étiquette "interactive" s'applique à un shell que vous avez démarré. Ce ne sont pas des définitions d'actions car elles ne donnent aucune implication sur cette étiquette.

Cependant, je vois que dans le reste de la page de manuel Bash sont des références parsemées au shell se comportant de certaines manières "à moins qu'il ne s'agisse d'un shell interactif" ou "uniquement dans des shells interactifs, ou si l'option _____ est définie". (Il existe de nombreux exemples et ce n'est pas le point principal de cette question.)

J'accepte donc que "interactif" soit juste une étiquette pratique pour la collection de comportements "interactifs" par défaut (paramètres d'options) décrits dans le reste de la page de manuel. Ce n'est pas un terme ou un objet fondamental en soi; il n'a pas de définition faisant autorité en dehors du code source du shell. (Contrairement, par exemple, aux termes "descripteur de fichier ouvert" ou "processus arrêté" qui se réfèrent à des abstractions intégrées à la conception du noyau lui-même.)

(Bien qu'elle soit également définie dans la définition POSIX de sh, cette page de manuel [ man 1p sh] a beaucoup moins d'utilisations de "à moins que le shell soit interactif" et d'instructions similaires qu'auparavant man bash, et se concentre presque exclusivement sur les différences de temps d'invocation, donc je me concentrerai sur Bash à partir de ce point.)


Certaines des implications d'un shell "interactif" ne sont de toute façon pertinentes qu'au moment de l'invocation , comme les fichiers provenant du shell avant qu'il ne lise d'autres commandes. Cependant, il y a des implications (au moins dans Bash) qui sont pertinentes à tout moment. Il doit donc y avoir un moyen de dire, pour tout shell en cours d'exécution , s'il est interactif ou non.

L'exécution set +idans un shell Bash interactif entraîne la suppression de «i» du contenu de $-.

La question est: cela signifie-t-il que le shell n'est plus interactif?

Selon la définition exacte de Bash, cela ne devrait pas, car nulle part dans la définition il n'est requis que «i» soit présent dans $-:

   An interactive shell is one started without  non-option  arguments  and
   without the -c option whose standard input and error are both connected
   to terminals (as determined by isatty(3)), or one started with  the  -i
   option.

Une lecture stricte de la définition exacte soulève également la question: si le stdin ou le stderr d'un terminal interactif sont redirigés afin qu'ils ne soient plus connectés aux terminaux, le shell devient-il non interactif?

(Il semble que la réponse à celle-ci soit "non" et la page de manuel aurait pu inclure le modificateur: "dont l'entrée standard et l'erreur sont toutes deux connectées aux terminaux ... au moment de l'invocation ", mais je ne sais pas définitivement.)


Si la réponse est «Non, un shell ne peut pas devenir non interactif, ni vice versa», alors quelle est la manière définitive de déterminer si le shell est interactif?

Autrement dit: s'il y a des comportements d'un "shell interactif" qui persistent après set +i, qu'est-ce qui est utilisé pour déterminer que ces comportements doivent continuer à s'appliquer?


De peur que personne n'en doute: il existe des comportements d'un shell invoqué interactivement qui persistent après set +iet des comportements d'un shell invoqué de manière non interactive qui persistent après set -i. Pour un exemple, considérons l'extrait suivant de man bash:

COMMENTS
   In a non-interactive shell, or an interactive shell in which the inter-
   active_comments  option  to  the  shopt  builtin  is enabled (see SHELL
   BUILTIN COMMANDS below), a word beginning with # causes that  word  and
   all  remaining  characters  on that line to be ignored.  An interactive
   shell without the interactive_comments option enabled  does  not  allow
   comments.  The interactive_comments option is on by default in interac-
   tive shells.

Ainsi, en désactivant l' interactive_commentsoption, nous pouvons voir une différence entre les shells interactifs et non interactifs. La persistance de cette différence est démontrée par le script suivant:

#!/bin/bash

# When the testfile is run interactively,
# all three comments will produce an error
# (even the third where 'i' is not in '$-').
# When run noninteractively, NO comment will
# produce an error, though the second comment
# is run while 'i' IS in '$-'.

cat >testfile <<'EOF'
shopt interactive_comments
shopt -u interactive_comments
shopt interactive_comments
echo $-
#first test comment
set -i
echo $-
#second test comment
set +i
echo $-
#third test comment
EOF

echo 'running bash -i <testfile'
bash -i <testfile
echo 'running bash <testfile'
bash <testfile

Cela confirme que "interactif" et "a ila valeur de $-" ne sont pas équivalents.

Un test similaire utilisant ${parameter:?word}un paramètre non défini produit des résultats similaires, confirmant à nouveau que ce $-n'est pas la "source de vérité" pour l'interactivité du shell.


Alors, enfin, où est stocké le trait «d'interactivité» définitif d'un shell?

Et, un shell interactif peut-il devenir non interactif ou vice versa? (... en changeant ce trait?)

Caractère générique
la source

Réponses:

9

La question que je poserais serait pourquoi quelqu'un voudrait-il faire cela?

Vous pouvez désactiver certains aspects des shells interactifs comme:

  • PS1= PS2= désactiver les invites
  • set +m désactiver le contrôle des travaux
  • désactiver l'historique dans certains shells
  • vous pourrez peut-être décharger le zleet tous les modules d'achèvement dans zsh.

Mais si vous voulez que le shell cesse d'être interactif, vous pouvez faire à la place:

. /some/file; exit

Pour lui dire d'obtenir le reste des commandes de /some/file(remplacer par /dev/ttysi vous voulez toujours que les commandes soient lues à partir du périphérique tty), bien qu'il y ait toujours des différences par rapport aux shells non interactifs, comme pour le comportement returnou le fait qu'il ferait toujours le contrôle de l'emploi ou:

exec myshell /dev/tty

Pour remplacer votre shell interactif actuel par un shell non interactif qui lit toujours les commandes du périphérique tty.

Notez qu'avec bash 4.4, set +iretourne avec un bash: set: +i: invalid optionlike dans la plupart des autres shells.

Stéphane Chazelas
la source
Tout à fait d'accord, ce serait une chose ridicule à faire. Mon concept d '"interactif", comme je l'ai mentionné, est que ce n'est qu'une collection de comportements par défaut qui sont utiles lorsque vous interagissez avec votre shell. Si vous pouvez modifier chacun de ces comportements individuellement et que vous changez chacun d'eux, la question "Est-ce toujours un shell interactif?" est juste une sémantique ridicule; ce n'est même pas une question importante. Cependant ....
Wildcard
1
@Wildcard, si vous le faites exec < <(sleep infinity)dans un shell interactif, vous avez un shell interactif qui n'est pas très interactif. Le shell se considérerait toujours comme interactif car $-il contiendrait toujours i, mais vous pourriez ne pas. Je ne suis pas sûr qu'il y ait beaucoup plus à discuter à ce sujet.
Stéphane Chazelas
2
@Wildcard, si le shell a été démarré en tant que interactive, il le restera. Le fait que vous puissiez le faire set +idans les anciennes versions de bash était un bug.
Stéphane Chazelas
1
@Wildcard, Si vous regardez le code source de bash, vous trouverez probablement une interactivevariable booléenne globale qui correspond au idrapeau de $-. Changer ce booléen ne changera pas automatiquement tous les comportements des shells interactifs. Le passage de interactif à non interactif n'est pas pris en charge.
Stéphane Chazelas
4
@Wildcard Dash accepte set +iet cesse d'afficher une invite. C'est quelque chose que l'utilisateur n'est pas censé faire, il n'est donc pas surprenant que le comportement dépende du shell et soit souvent accidentel plutôt que le résultat d'une décision délibérée de la part de son implémenteur.
Gilles 'SO- arrête d'être méchant'