In a Linux and shell context, what is the difference between a "login shell", an "interactive shell" and any other kind of logged-in mode?
In the context of Linux and shell, there are several types of shells that can be opened, including login shells, interactive shells, and non-interactive shells. Here's a brief explanation of these types:
- Login Shell: A login shell is the first shell that is run when you log into a Unix-based system. This shell reads your profile file (like ~/.bash_profile, ~/.bash_login, or ~/.profile) to set environment variables and settings. A login shell typically ends with a shell prompt for user input.
- Interactive Shell: An interactive shell is a shell session that is ready to take commands from the user. It's "interactive" because it interacts directly with the user. Both login shells and non-login shells can be interactive. In an interactive shell, command history is kept, and the shell reads and executes the ~/.bashrc file upon startup.
- Non-Interactive Shell: A non-interactive shell is typically a shell session that runs a script or a command. It does not interact with the user. It's often used in a scripting context or when a shell script is invoked from a non-shell application. In non-interactive mode, the shell runs commands from a file or input pipeline, and then exits when it's done. It doesn't read the ~/.bashrc file.
- Non-Login Shell: A non-login shell is a shell that is started after the login process, and it does not execute the login scripts like ~/.bash_profile or ~/.profile. Typically, when you open a new terminal window in your desktop environment, it opens a non-login shell. These shells source the ~/.bashrc file.
In summary, whether a shell is a login shell or not determines which initialization files it reads when it starts up. Whether a shell is interactive or not determines whether it interacts with the user or not (taking user commands and showing results).
Note that a shell can be a combination of the above. For example, when you first login to a Linux terminal, you typically get an "interactive login shell". When you open a new terminal window in your desktop environment, you typically get an "interactive non-login shell". If a script is run on system startup or by a scheduler like cron, it's typically run in a "non-interactive non-login shell".
What is it called when you log into a GUI and never fire up a terminal?
When you log into a graphical user interface (GUI) without explicitly opening a terminal, you are typically using what's known as a "desktop environment" or "windowing system".
In Linux, there are many popular desktop environments such as GNOME, KDE, XFCE, and so on. These environments allow you to interact with the system through graphical components like icons, windows, toolbars, wallpapers, and other elements, rather than strictly through a command-line interface.
Although you might not explicitly open a terminal, the desktop environment itself is usually running on top of a variety of underlying processes, which can include shell processes. For example, many of your system's startup scripts are run in non-interactive shells during the boot process. These scripts start the services that make up your GUI, among other things.
Furthermore, when you use GUI applications to perform actions on your system (like copying files, connecting to a network, etc.), these applications often invoke shell commands or system APIs in the background. But in terms of user interaction, if you're not opening a terminal, you're not directly using a shell—you're using a desktop environment or windowing system.
Which dotfiles or rc-files, if any, are read when you log into a GUI?
The answer depends on the specifics of the Linux distribution and the desktop environment being used, as well as the specific configurations of these systems. However, here are some general guidelines:
- Xinitrc and Xsession: If you're using the X Window System (commonly just called "X"), the ~/.xinitrc and ~/.xsession files can be used to customize the startup of your X session. They're not always used, and their usage depends on how X is started. Some display managers (the programs that provide a graphical login prompt) use one of these files, or similar files located elsewhere.
- Desktop Environment Specific Files: Some desktop environments have their own specific files that are read upon login. For example:GNOME may use ~/.gnomerc.KDE may use ~/.kde/Autostart/ directory for scripts to run at startup.
- GNOME may use ~/.gnomerc.
- KDE may use ~/.kde/Autostart/ directory for scripts to run at startup.
- Bash or Shell Files: While it's less common, some graphical login processes might source ~/.bash_profile, ~/.bashrc, ~/.profile, or similar files. However, this depends heavily on the specifics of the system configuration, and it's not something you can count on for all systems.
- Configurations in GUIs: Most desktop environments also allow you to set applications to start at login through their graphical interface, without the need to directly modify any files. These settings are typically stored in configuration files that are specific to each desktop environment, and they're usually not considered "dotfiles" in the traditional sense.
Remember that the above can vary greatly depending on the specifics of the system. If you're trying to ensure that a certain command or script runs when you log into your GUI, you'll need to check the documentation for your specific desktop environment and Linux distribution.
Where would you set environment variables that you wanted to be present/available in the GUI login session, without having opened a terminal?
Setting environment variables so they are available in a graphical (GUI) login session depends on your specific desktop environment and distribution, as different systems handle this in different ways. Here are some general methods:
-
PAM (Pluggable Authentication Module): On many Linux systems, you can set environment variables in the /etc/environment file. This file is read by the PAM during the login process and is not specific to any shell, so variables set here should be available to GUI applications as well.This file just contains variable assignments like:makefileCopy codeVARNAME="value"
-
Shell Profile Files: Depending on how your system is configured, it might source ~/.profile, ~/.bash_profile, or similar files during the login process, even for graphical logins. You can set environment variables in these files, and they might be picked up by your desktop environment. However, this is not always reliable, as not all systems (or all sessions) will source these files on graphical login.
-
Desktop Environment Specific Methods: Some desktop environments have their own methods for setting environment variables:GNOME: You can use the ~/.gnomerc script to set environment variables. This script is run whenever you start a GNOME session.KDE: For KDE, you can create a shell script setting the needed environment variables, and place it in ~/.config/plasma-workspace/env/.
-
GNOME: You can use the ~/.gnomerc script to set environment variables. This script is run whenever you start a GNOME session.
-
KDE: For KDE, you can create a shell script setting the needed environment variables, and place it in ~/.config/plasma-workspace/env/.
-
Systemd: If your system uses systemd, you can use a systemd user service that starts with your session to set environment variables. This is a more complex method and requires a deeper understanding of systemd.
-
Xorg Session Scripts: If you're using the X Window System, you can set environment variables in ~/.xsessionrc.
Remember to log out and log back in, or reboot the system to make sure changes take effect.
Please note that you need to be careful when modifying these files or settings, as incorrect settings can cause issues with your system. Always make a backup of any file before you modify it.
I use GNOME, I don't use Wayland, and I'm on NixOS. I'm trying to come up with a config that I can use across both Linux and my macOS laptop, all on Bash.
I've never nailed this down. I see 3 different contexts:
-
Script that is run as me without any interaction (like via crond) and needs some kind of environment (or doesn't).
-
Logging in via a GUI, no shell is fired up, but I might want some environment variables to be set anyway that are accessible from GUI processes I trigger.
-
Opening an actual shell and getting to a TUI/REPL. This might expect all possible environmental setup to run first.
If I'm on Linux and use Bash, which files should I put the relevant config into to handle these 3 situations properly? For example, obviously, PS1 doesn't need to be set for the first 2, HOME might need to be set for all of them, and depending on what the function does, I might want certain bash functions or aliases I define to be available from 1, 3 or both. Running Steam from a GUI means that I might want certain Steam environment variables set for case 2, etc.
My second question is, how does this answer differ in macOS?
My third question is, which of these are login shells? non-login shells? interactive shells? non-interactive shells? Is there a use-case I'm missing in my 3 examples?
My fourth question is, how would I force the config to be re-read in each context? 3 is much more obvious than 2, 1 is unlikely to need such a thing. For 3, I defined an alias called "rehash": alias rehash='source "$HOME/.bash_profile"'
but now I'm hearing this is actually wrong.
You've got a lot of questions here, so let's take them one at a time.
First Question: Bash Configuration Files for Different Contexts
- Non-Interactive Scripts (like crond): For non-interactive scripts, environment variables should ideally be set within the script itself or in the crontab file. However, if you need to set environment variables that will be available to all cron jobs, you can set them in your ~/.bashrc or ~/.bash_profile files. Note that you may need to explicitly source these files in the scripts, as cron jobs run in a minimal environment.
- GUI Login (no shell): For GNOME, you can set environment variables in ~/.gnomerc or ~/.profile. The ~/.gnomerc file is specifically sourced when a GNOME session starts, and ~/.profile is a more general file that is sourced upon login by most Unix-like systems, including macOS. Note that you might need to log out and log back in for these changes to take effect.
- Interactive Shell: For an interactive bash shell, you can set environment variables in ~/.bashrc or ~/.bash_profile. The ~/.bashrc file is sourced by each new non-login shell, and ~/.bash_profile (or ~/.profile if ~/.bash_profile doesn't exist) is sourced by each new login shell. Note that on some systems, ~/.bash_profile sources ~/.bashrc, but this is not always the case.
Second Question: macOS Differences
On macOS, the Terminal app runs a login shell by default each time it's started. So, you should set environment variables in ~/.bash_profile
for them to be available in Terminal. Note that this behavior can be changed in Terminal's settings.
For GUI applications on macOS, you can set environment variables in ~/.launchd.conf
or ~/Library/LaunchAgents/my.startup.plist
. Note that changes to these files will only take effect after a logout or a reboot.
Third Question: Shell Types
In your three scenarios:
- Scripts run as you without any interaction (like via crond) are in a non-interactive non-login shell.
- Logging in via a GUI does not involve a shell, but subsequent commands run from the GUI (e.g., via "Run Command" dialogs) are usually run in non-interactive non-login shells.
- Opening an actual shell and getting to a TUI/REPL is typically an interactive non-login shell, if you're opening the shell from an existing session (like opening a terminal window in a GUI). If you're logging into a session via the shell (like ssh-ing into a remote machine), it's an interactive login shell.
Fourth Question: Reloading Configurations
For scenario 1, you would need to restart the cron job or service for changes to take effect. For scenario 2, you would need to log out and log back in for changes to take effect. For scenario 3, you can source the relevant file, e.g., source ~/.bashrc
or source ~/.bash_profile
.
Your "rehash" alias is not necessarily "wrong," but it might not always do what you expect. For example, if you've set variables in ~/.bashrc
, those won't be reloaded by your "rehash" alias. To ensure you're sourcing the correct file, you might want to create separate aliases for ~/.bashrc
and ~/.bash_profile
, or have one alias that sources both files.
Oh, my .bash_profile
actually loads .bashrc
as well
That's a common setup. With that setup, ~/.bash_profile
is sourced by login shells and ~/.bashrc
is sourced by non-login shells, but because ~/.bash_profile
sources ~/.bashrc
, settings in ~/.bashrc
are also applied to login shells.
With this setup, here's how you could handle your three scenarios:
- Non-Interactive Scripts (like crond): If you need to set environment variables that will be available to all cron jobs, you can set them in ~/.bashrc. Because your ~/.bash_profile sources ~/.bashrc, these variables will also be available in login shells.
- GUI Login (no shell): For GNOME on NixOS, you can set environment variables in ~/.profile. Even though ~/.profile is not typically read when ~/.bash_profile exists, GNOME specifically sources ~/.profile when starting a session. This way, the environment variables will be available for the GUI session.
- Interactive Shell: You can set environment variables in ~/.bashrc. Because ~/.bash_profile sources ~/.bashrc, these variables will also be available in login shells.
For your "rehash" alias, given that your ~/.bash_profile
sources ~/.bashrc
, source "$HOME/.bash_profile"
should effectively reload configurations from both files. Just make sure you run the rehash
command in an interactive shell.
Remember, the actual files used can vary depending on the specific system and configuration, but this is a common setup and will likely work in your case. Also, bear in mind that to apply changes to environment variables in running processes or applications, you usually need to restart those processes or applications.
ChatGPT, you are a stellar tutor. I will experiment with these configs, although I may or may not report back if they work. You'll probably hear from me if they don't, though, lol, but that's only because you're so helpful
Thank you so much for your kind words! I'm glad to hear you found the information helpful. Don't hesitate to ask if you have any more questions or run into issues with your configurations. I'm here to help. Happy experimenting, and I hope everything works out well for you!