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 shell’s 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 sh
dé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 +i
dans 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 +i
et 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_comments
option, 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 i
la 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?)
la source
Réponses:
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 invitesset +m
désactiver le contrôle des travauxzle
et tous les modules d'achèvement danszsh
.Mais si vous voulez que le shell cesse d'être interactif, vous pouvez faire à la place:
Pour lui dire d'obtenir le reste des commandes de
/some/file
(remplacer par/dev/tty
si 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 comportementreturn
ou le fait qu'il ferait toujours le contrôle de l'emploi ou: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 +i
retourne avec unbash: set: +i: invalid option
like dans la plupart des autres shells.la source
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 toujoursi
, mais vous pourriez ne pas. Je ne suis pas sûr qu'il y ait beaucoup plus à discuter à ce sujet.interactive
, il le restera. Le fait que vous puissiez le faireset +i
dans les anciennes versions de bash était un bug.bash
, vous trouverez probablement uneinteractive
variable booléenne globale qui correspond aui
drapeau 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.set +i
et 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.