Différence entre shell de connexion et shell de non-connexion?

318

Je comprends la différence fondamentale entre un shell interactif et un shell non interactif. Mais qu'est-ce qui différencie exactement un shell de connexion d'un shell non-login?

Pouvez-vous donner des exemples d'utilisation d'un shell interactif sans connexion ?

Igorio
la source
45
Je pense que la question est mieux formulée comme suit: " Pourquoi devons-nous / devrions-nous nous soucier de différencier les shells avec et sans login?" De nombreux endroits sur le Web nous disent déjà quelles sont les différences, en termes de fichiers de démarrage lus par chaque fichier; mais aucun d'entre eux ne semble répondre au "pourquoi" de manière satisfaisante et convaincante. Des exemples de cas d'utilisation où vous ne voudrez certainement pas l' un ou l'autre comportement seraient formidables.
Kal
2
@Kal Cela devrait être une question différente, car aucune réponse ne couvre réellement cette question. Edit: En fait, la voici: POURQUOI un shell de connexion sur un shell non-login ? .
Skippy le Grand Gourou

Réponses:

304

Un shell de connexion est le premier processus qui s'exécute sous votre ID utilisateur lorsque vous vous connectez pour une session interactive. Le processus de connexion indique au shell de se comporter comme un shell de connexion avec une convention: passer l'argument 0, qui est normalement le nom de l'exécutable du shell, avec un -caractère ajouté (par exemple -bashalors qu'il le serait normalement) bash. Les shells de login lisent généralement un fichier qui des choses comme la définition des variables d'environnement: /etc/profileet ~/.profilepour la coquille traditionnelle Bourne, en ~/.bash_profileplus pour bash , /etc/zprofileet ~/.zprofilepour zsh , /etc/csh.loginet ~/.loginpour csh, etc.

Lorsque vous vous connectez à une console de texte, via SSH ou avec su -, vous obtenez un shell de connexion interactif . Lorsque vous vous connectez en mode graphique (sur un gestionnaire d'affichage X ), vous ne disposez pas d'un shell de connexion, mais d'un gestionnaire de session ou d'un gestionnaire de fenêtres.

Il est rare d’exécuter un shell de connexion non interactif , mais certains paramètres X le font lorsque vous vous connectez avec un gestionnaire d’affichage afin de pouvoir lire les fichiers de profil. D'autres paramètres (cela dépend de la distribution et du gestionnaire d'affichage) sont lus /etc/profileet ~/.profileexplicitement, ou ne les lisent pas. Pour obtenir un shell de connexion non interactif, vous pouvez également vous connecter à distance à l'aide d'une commande transmise via une entrée standard qui n'est pas un terminal, par exemple ssh example.com <my-script-which-is-stored-locally(par opposition à ssh example.com my-script-which-is-on-the-remote-machine, qui exécute un shell non interactif et non connecté).

Lorsque vous démarrez un shell dans un terminal dans une session existante (écran, terminal X, tampon de terminal Emacs, shell dans un autre, etc.), vous obtenez un shell interactif sans connexion . Ce shell peut lire un fichier de configuration du shell ( ~/.bashrcpour bash invoquée bash, /etc/zshrcet ~/.zshrcpour zsh, /etc/csh.cshrcet ~/.cshrcpour csh, le fichier indiqué par la ENVvariable pour POSIX / coquilles XSI conformes tels que tableau de bord, ksh et bash lorsqu'il est invoqué comme sh, $ENVsi elle est définie et ~/.mkshrcpour mksh, etc.).

Lorsqu'un shell exécute un script ou une commande passée sur sa ligne de commande, il s'agit d'un shell non interactif et non connecté . De tels shells fonctionnent tout le temps: il est très courant que lorsqu'un programme appelle un autre programme, il exécute un minuscule script dans un shell pour appeler cet autre programme. Certains shells lisent un fichier de démarrage dans ce cas (bash exécute le fichier indiqué par la BASH_ENVvariable, zsh exécute /etc/zshenvet ~/.zshenv), mais cela présente un risque: le shell peut être appelé dans toutes sortes de contextes, et vous ne pouvez pratiquement rien faire de tel casser quelque chose.

Je simplifie un peu, voir le manuel pour les détails sanglants.

Gilles
la source
2
Pouvez-vous donner un exemple d'utilisation en bashtant que shell de connexion non interactif?
Piotr Dobrogost
13
@PiotrDobrogostecho $- | bash -lx
Gilles
1
Je ne sais pas si cela est vrai en général, mais je tiens à noter que lorsque j'ouvre un nouveau terminal (sous osx avec les paramètres par défaut), je reçois un shell de connexion même si je ne tape jamais mon nom d'utilisateur ou mon mot de passe.
Kevin Wheeler
4
@KevinWheeler Sous OSX, par défaut, l'application Terminal exécute un shell de connexion. (Comme je l'explique, le programme qui lance le shell décide si celui-ci agit comme un shell de connexion.) Ce n'est pas la façon habituelle de faire les choses.
Gilles
2
@IAmJulianAcosta Si FOOest une variable d'environnement (c'est-à .profile- dire contient export FOO=something), elle est disponible pour tous les sous-processus, y compris foo.sh. Si vous changez .profiled' export FOO=something_elsealors ./foo.shimprimera somethingjusqu'à ce que la prochaine fois que vous vous connectez.
Gilles
48

Pour savoir si vous êtes dans un shell de connexion:

prompt> echo $0
-bash # "-" is the first character. Therefore, this is a login shell.

prompt> echo $0
bash # "-" is NOT the first character. This is NOT a login shell.

Dans Bash, vous pouvez également utiliser shopt login_shell:

prompt> shopt login_shell
login_shell     off

(ou ondans un shell de connexion).

Des informations peuvent être trouvées dans man bash(recherche d'invocation). Voici un extrait:

Un shell de connexion est un shell dont le premier caractère de l'argument zéro est un - ou un caractère commençant par l'option --login.

Vous pouvez tester cela vous-même. Chaque fois que vous SSH, vous utilisez un shell de connexion. Par exemple:

prompt> ssh user@localhost
user@localhost's password:
prompt> echo $0
-bash

L'importance d'utiliser un shell de connexion est que tous les paramètres /home/user/.bash_profileseront exécutés. Voici un peu plus d'informations si vous êtes intéressé (de man bash)

"Lorsque bash est appelé en tant que shell de connexion interactif, ou en tant que shell non interactif avec l'option --login, il commence par lire et exécuter les commandes du fichier / etc / profile, si ce fichier existe. Après la lecture de ce fichier, il regarde pour ~/.bash_profile, ~/.bash_loginet ~/.profile, dans cet ordre, et lit et exécute les commandes de la première qui existe et est lisible. l'option --noprofile peut être utilisé lorsque la coquille commence à inhiber ce comportement « .

Timothy Pulliam
la source
23

Dans une coquille de connexion, argv[0][0] == '-'. Voici comment il sait que c'est un shell de connexion.

Et dans certaines situations, il se comporte différemment selon son statut de "shell de connexion". Par exemple, un shell, qui n'est pas un shell de connexion, n'exécute pas une commande "logout".

BOPOHOK
la source
4
Selon man bash, avec une emphase ajoutée, "Un shell de connexion est un shell dont le premier caractère de l'argument zéro est un -, ou un code commençant par l'option --login. "
Wildcard
18

Un shell démarré dans un nouveau terminal dans une interface graphique serait un shell interactif sans connexion. Cela aurait pour source votre .bashrc, mais pas votre .profile, par exemple.

julien
la source
4

Je développerai l'excellente réponse de Gilles, associée à la méthode de vérification du type de shell de connexion de Timothy.

Si vous aimez voir des choses par vous-même, essayez les extraits et les scénarios ci-dessous.

Vérifier si le shell est (non) interactif

if tty -s; then echo 'This is interactive shell.'; else echo 'This is non-interactive shell.'; fi

Vérifier si le shell est (non) connecté

Si la sortie echo $0commence par -, c'est un shell de connexion ( echo $0exemple de sortie:) -bash. Sinon, c'est un shell non-login ( echo $0exemple de sortie:) bash.

if echo $0 | grep -e ^\- 2>&1>/dev/null; then echo "This is login shell."; else echo "This is non-login shell."; fi;

Associons les deux éléments ci-dessus pour obtenir les deux informations à la fois:

THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; 
THIS_SHELL_LOGIN_TYPE='non-login'; 
if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; 
if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

Scénarios:

Session SSH typique sans options spéciales

ssh ubuntu@34.247.105.87
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

ubuntu@ip-172-31-0-70:~$ THIS_SHELL_INTERACTIVE_TYPE='non-interactive';
ubuntu@ip-172-31-0-70:~$ THIS_SHELL_LOGIN_TYPE='non-login';
ubuntu@ip-172-31-0-70:~$ if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi;
ubuntu@ip-172-31-0-70:~$ if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
ubuntu@ip-172-31-0-70:~$ echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

interactive/login

Exécution d'un script ou exécution explicite via un nouveau shell

ubuntu@ip-172-31-0-70:~$  bash -c 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; 
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

Exécuter un script local à distance

ssh ubuntu@34.247.105.87 < checkmy.sh
Pseudo-terminal will not be allocated because stdin is not a terminal.
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

non-interactive/login

Exécuter une commande sur ssh à distance

ssh ubuntu@34.247.105.87 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

non-interactive/non-login

Exécuter une commande sur ssh à distance avec -tswitch

Vous pouvez demander explicitement un shell interactif lorsque vous souhaitez exécuter une commande à distance via ssh en utilisant -tswitch.

ssh ubuntu@34.247.105.87 -t 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

Remarque: Pourquoi exécuter une commande à distance n’est pas login shellplus utile ici .

Patrik Stas
la source