Purpose of [ -n â$PS1â ] in bashrc

Clash Royale CLAN TAG#URR8PPP
up vote
10
down vote
favorite
What purpose does the [ -n "$PS1" ] in [ -n "$PS1" ] && source ~/.bash_profile; serve? This line is included in a .bashrc of a dotfiles repo.
bash osx bashrc
add a comment |Â
up vote
10
down vote
favorite
What purpose does the [ -n "$PS1" ] in [ -n "$PS1" ] && source ~/.bash_profile; serve? This line is included in a .bashrc of a dotfiles repo.
bash osx bashrc
add a comment |Â
up vote
10
down vote
favorite
up vote
10
down vote
favorite
What purpose does the [ -n "$PS1" ] in [ -n "$PS1" ] && source ~/.bash_profile; serve? This line is included in a .bashrc of a dotfiles repo.
bash osx bashrc
What purpose does the [ -n "$PS1" ] in [ -n "$PS1" ] && source ~/.bash_profile; serve? This line is included in a .bashrc of a dotfiles repo.
bash osx bashrc
bash osx bashrc
edited Aug 15 at 5:05
msp9011
3,46643862
3,46643862
asked Aug 15 at 4:40
shotes
594
594
add a comment |Â
add a comment |Â
4 Answers
4
active
oldest
votes
up vote
19
down vote
accepted
This is checking whether the shell is interactive or not. In this case, only sourcing the ~/.bash_profile file if the shell is interactive.
See "Is this Shell Interactive?" in the bash manual, which cites that specific idiom. (It also recommends checking whether the shell is interactive by testing whether the $- special variable contains the i character, which is a better approach to this problem.)
bash, at least, will unset PS1 and PS2 if the shell is interactive. You can see that for yourself, with( export PS1='abc$ '; bash -c 'echo "[$PS1]"' ), which simply prints. It seems zsh does not do the same, at least from an experiment... In any case, the intention of the[ -n "$PS1" ]is to check whether the shell is interactive or not.
â Filipe Brandenburger
Aug 15 at 6:59
3
Thatbashunsets PS1 when non-interactive (typo in your previous comment) is a bug IMO, PS1 is not a bash-specific variable, it has no business unsetting it. It's the only shell that does that (thoughyashalso setsPS1to a default value even when non-interactive).
â Stéphane Chazelas
Aug 15 at 7:20
1
Since the code in question is in a bash-specific file, this seems like a reasonable answer. Other answers address the more-general case of POSIX specs or other shells. YouâÂÂve answered the âÂÂwhat is the purpose of this?â intention in the Question while appropriately leaving aside the rest. ItâÂÂs good to know what bash is doing and possibly better ways to accomplish the goal, too.
â Jeff Schaller
Aug 15 at 10:33
I would consider this answer more complete if it suggested a more reliable alternative (say,[[ $- = *i* ]] && source ~/.bash_profile).
â Charles Duffy
Aug 15 at 19:48
@CharlesDuffy Frankly I don't think there's much wrong with[ -n "$PS1" ], but I have still updated my answer to highlight that the bash manual also suggests/recommends inspecting$-to determine whether the shell is interactive, I hope you find that improves the answer. Cheers!
â Filipe Brandenburger
Aug 16 at 1:39
 |Â
show 2 more comments
up vote
19
down vote
What this does
This is a widespread way of testing whether the shell is interactive. Beware that it only works in bash, it doesn't work with other shells. So it's ok (if silly) for .bashrc, but it wouldn't work in .profile (which is read by sh, and bash is only one of the possible implementations of sh, and not the most common one).
Why it works (in bash only!)
An interactive shell sets the shell variable PS1 to the default prompt string. So if the shell is interactive, PS1 is set (unless the user's .bashrc has removed it, which can't have happened yet at the top of .bashrc, and you could consider that it's a silly thing to do anyway).
The converse is true in bash: non-interactive instances of bash unset PS1 when they start. Note that this behavior is specific to bash, and is arguably a bug (why would bash -c '⦠do stuff with $varâ¦' not work when var is PS1?). But all versions of bash up to and including 4.4 (the latest version as I write) do this.
Many systems export PS1 to the environment. It's a bad idea, because many different shells use PS1 but with a different syntax (e.g. bash's prompt escapes are completely different from zsh's prompt escapes). But it's widespread enough that in practice, seeing that PS1 is set is not a reliable indicator that the shell is interactive. The shell might have inherited PS1 from the environment.
Why it's (mis)used here
.bashrc is the file that bash reads at startup when it's interactive. A less well-known fact is that bash also reads .bashrc is a login shell and bash's heuristics conclude that this is a remote session (bash checks if its parent is rshd or sshd). In this second case, it's unlikely that PS1 would be set in the environment, because no dot file has run yet.
However, the way the code uses this information is counterproductive.
- If the shell is an interactive shell, then this runs
.bash_profilein that shell. But.bash_profileis a login-time script. It might run some programs that are intended to be run only once per session. It might override some environment variables that the user had deliberately set to a different value before running that shell. Running.bash_profilein a non-login shell is disruptive. - If the shell is a non-interactive remote login shell, it won't load
.bash_profile. But this is the case where loading.bash_profilecould be useful, because a non-interactive login shell doesn't automatically load/etc/profileand~/.profile.
I think the reason people do this is for users who log in through a GUI (a very common case) and who put their environment variable settings in .bash_profile rather than .profile. Most GUI login mechanisms invoke .profile but not .bash_profile (reading .bash_profile would require running bash as part of the session startup, instead of sh). With this configuration, when the user opens a terminal, they'll get their environment variables. However, the user will not get their environment variables in GUI applications, which is a very common source of confusion. The solution here is to use .profile instead of .bash_profile to set environment variables. Adding a bridge between .bashrc and .bash_profile creates more problems than it solves.
What to do instead
There's a straightforward, portable way of testing whether the current shell is interactive: test whether the option -i is enabled.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
This is useful in .bashrc to read .profile only if the shell is non-interactive âÂÂài.e. the opposite of what the code does! Read .profile if bash is a (non-interactive) login shell, and don't read it if it's an interactive shell.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
4
Might be worth noting that a better way to test if a shell is interactive is with[[ -o interactive ]](ksh, bash, zsh) orcase $- in (*i*) ...; esac(POSIX)
â Stéphane Chazelas
Aug 15 at 6:51
2
My bash (version 4.4.12) actually seems to unsetPS1if not run interactively. It is easy enough to test:PS1=cuckoo bash -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'will not print anything, whilePS1=cuckoo bash -i -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'prints the value of$PS1set in your bash startup files (it will not print the string "cuckoo").
â FooF
Aug 15 at 8:10
1
@Stéphane Chazelas: POSIX does not require that$-containsiwith an interactive shell.
â schily
Aug 15 at 9:20
1
Bosh does this since 2012 to be compatible to ksh. It just was not required by POSIX until the change you mantion becomes effective.
â schily
Aug 15 at 12:42
1
Frankly, I'd say calling[ -n "$PS1" ]wrong is going a bit too far, after all it only breaks when someone is exporting PS1 (which in your answer you say it's a bad idea and even go into the reasons why) and that doesn't affect bash anyways (since it unsets PS1 and PS2 if the shell is non-interactive.) Maybe using a word such as "discouraged" or talking about the "limitations" of the approach would have been better. I don't think it's "wrong" altogether. If anything is wrong is exporting PS1, that's for sure! Anyways, thanks for going into the details of this.
â Filipe Brandenburger
Aug 16 at 1:33
 |Â
show 3 more comments
up vote
1
down vote
It seems that this strange concept is a result from the fact that bash did not start as a POSIX shell clone but as a Bourne Shell clone.
As a result, the POSIX interactive behavior ($ENV gets called for interactive shells) has been added later to bash and is not widely known.
There is one shell that grants similar behavior. This is csh and csh grants that $prompt has specific values:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
But this neither applies to the Bourne Shell nor to POSIX shells.
For a POSIX shell, the only granted method is to put code for interactive shells into the file:
$ENV
that has a shell specific name. It is e.g.
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Other people mentioned the shell flag -i, but this is not usable for reliable programming. POSIX neither requires that set -i works, nor that $- contains an i for interactive shells. POSIX just requires that sh -i enforces the shell into the interactive mode.
Since the variable $PS1 can be imported from the environment, it may have a value even in non-interactive mode. The fact that bash unsets PS1 in any non-interactive shell is not granted by the standard and not done by any other shell.
So clean programming (even with bash) is to put the commands for interactive shells into $HOME/.bashrc.
add a comment |Â
up vote
0
down vote
I am going first to talk of what Debian, and most of the time also Ubuntu sets for bash. And latter touch on other systems.
In the setting of shell start files there is a lot of opinion.
I also have my opinion but I will try to show existing examples of correct settings.
I'll use debuan as it is quite easy to find examples of its files.
And debian is heavily used, so the settings have been well tested,
What is the goal of checking that PS1 is set?
Only to find out if the shell is interactive.
The default /etc/profile in debian and ubuntu (from /usr/share/base-files/profile):
if [ "$PS1-" ]; then
if [ "$BASH-" ] && [ "$BASH" != "/bin/sh" ]; then
The if's read: if interactive (PS1 default set) and it is a bash shell (but not acting as a default sh) then change PS1 to a particular new one (not the default one).
The default /etc/bash.bashrc in debian also contains:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Which is pretty clear in what it does: If interactive don't source (the rest).
However, in /etc/skel/.bashrc is an example of the correct way to test for an interactive shell (using $-):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
That should show clearly the why of PS1 and one alternative.
The correct order
The setting you are reporting should be avoided.
The order (from system settings to more specific user settings (for bash)) is /etc/profile, /etc/bash.bashrc, ~/.profile and finally ~/.bashrc. That places the most broad effects (and for more shells) in /etc/profile (which is owned by root) followed by /etc/bash.bashrc (which is also owned by root) but only affects bash. Then come the personal settings in $HOME, the first is ~/.profile for most shells and ~/.bashrc (almost equivalent to ~/.bash_profile), specific for bash only.
It is therefore wrong to source ~/.bashrc in ~/.profile, it is transforming an specific user setting for bash to a more general that is affecting more shells. Except if done in this way:
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
It checks that bash is running and only load .bashrc if that is the case.
This is an upstream decision coming from Debian. The rationale is explained here.
In fact, the reverse, sourcing ~/.profile in ~/.bash_profile (or ~/.bashrc) is only re-applying general rules that should had been loaded already to a particular use case, and therefore "not that bad" (I am not saying "good"). And I am not saying good because it may cause the sourcing of files to loop. Like when a sub-directory loads a parent, that is a directory loop.
And is in this cross sourcing that the check for interactive shell makes sense. Only when a shell is interactive is ~/.bashrc loaded, but it in turn may be loading ~/.profile (or the other way around) and is in this case that checking for an interactive shell could be used.
add a comment |Â
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
19
down vote
accepted
This is checking whether the shell is interactive or not. In this case, only sourcing the ~/.bash_profile file if the shell is interactive.
See "Is this Shell Interactive?" in the bash manual, which cites that specific idiom. (It also recommends checking whether the shell is interactive by testing whether the $- special variable contains the i character, which is a better approach to this problem.)
bash, at least, will unset PS1 and PS2 if the shell is interactive. You can see that for yourself, with( export PS1='abc$ '; bash -c 'echo "[$PS1]"' ), which simply prints. It seems zsh does not do the same, at least from an experiment... In any case, the intention of the[ -n "$PS1" ]is to check whether the shell is interactive or not.
â Filipe Brandenburger
Aug 15 at 6:59
3
Thatbashunsets PS1 when non-interactive (typo in your previous comment) is a bug IMO, PS1 is not a bash-specific variable, it has no business unsetting it. It's the only shell that does that (thoughyashalso setsPS1to a default value even when non-interactive).
â Stéphane Chazelas
Aug 15 at 7:20
1
Since the code in question is in a bash-specific file, this seems like a reasonable answer. Other answers address the more-general case of POSIX specs or other shells. YouâÂÂve answered the âÂÂwhat is the purpose of this?â intention in the Question while appropriately leaving aside the rest. ItâÂÂs good to know what bash is doing and possibly better ways to accomplish the goal, too.
â Jeff Schaller
Aug 15 at 10:33
I would consider this answer more complete if it suggested a more reliable alternative (say,[[ $- = *i* ]] && source ~/.bash_profile).
â Charles Duffy
Aug 15 at 19:48
@CharlesDuffy Frankly I don't think there's much wrong with[ -n "$PS1" ], but I have still updated my answer to highlight that the bash manual also suggests/recommends inspecting$-to determine whether the shell is interactive, I hope you find that improves the answer. Cheers!
â Filipe Brandenburger
Aug 16 at 1:39
 |Â
show 2 more comments
up vote
19
down vote
accepted
This is checking whether the shell is interactive or not. In this case, only sourcing the ~/.bash_profile file if the shell is interactive.
See "Is this Shell Interactive?" in the bash manual, which cites that specific idiom. (It also recommends checking whether the shell is interactive by testing whether the $- special variable contains the i character, which is a better approach to this problem.)
bash, at least, will unset PS1 and PS2 if the shell is interactive. You can see that for yourself, with( export PS1='abc$ '; bash -c 'echo "[$PS1]"' ), which simply prints. It seems zsh does not do the same, at least from an experiment... In any case, the intention of the[ -n "$PS1" ]is to check whether the shell is interactive or not.
â Filipe Brandenburger
Aug 15 at 6:59
3
Thatbashunsets PS1 when non-interactive (typo in your previous comment) is a bug IMO, PS1 is not a bash-specific variable, it has no business unsetting it. It's the only shell that does that (thoughyashalso setsPS1to a default value even when non-interactive).
â Stéphane Chazelas
Aug 15 at 7:20
1
Since the code in question is in a bash-specific file, this seems like a reasonable answer. Other answers address the more-general case of POSIX specs or other shells. YouâÂÂve answered the âÂÂwhat is the purpose of this?â intention in the Question while appropriately leaving aside the rest. ItâÂÂs good to know what bash is doing and possibly better ways to accomplish the goal, too.
â Jeff Schaller
Aug 15 at 10:33
I would consider this answer more complete if it suggested a more reliable alternative (say,[[ $- = *i* ]] && source ~/.bash_profile).
â Charles Duffy
Aug 15 at 19:48
@CharlesDuffy Frankly I don't think there's much wrong with[ -n "$PS1" ], but I have still updated my answer to highlight that the bash manual also suggests/recommends inspecting$-to determine whether the shell is interactive, I hope you find that improves the answer. Cheers!
â Filipe Brandenburger
Aug 16 at 1:39
 |Â
show 2 more comments
up vote
19
down vote
accepted
up vote
19
down vote
accepted
This is checking whether the shell is interactive or not. In this case, only sourcing the ~/.bash_profile file if the shell is interactive.
See "Is this Shell Interactive?" in the bash manual, which cites that specific idiom. (It also recommends checking whether the shell is interactive by testing whether the $- special variable contains the i character, which is a better approach to this problem.)
This is checking whether the shell is interactive or not. In this case, only sourcing the ~/.bash_profile file if the shell is interactive.
See "Is this Shell Interactive?" in the bash manual, which cites that specific idiom. (It also recommends checking whether the shell is interactive by testing whether the $- special variable contains the i character, which is a better approach to this problem.)
edited Aug 16 at 1:37
answered Aug 15 at 4:57
Filipe Brandenburger
3,734622
3,734622
bash, at least, will unset PS1 and PS2 if the shell is interactive. You can see that for yourself, with( export PS1='abc$ '; bash -c 'echo "[$PS1]"' ), which simply prints. It seems zsh does not do the same, at least from an experiment... In any case, the intention of the[ -n "$PS1" ]is to check whether the shell is interactive or not.
â Filipe Brandenburger
Aug 15 at 6:59
3
Thatbashunsets PS1 when non-interactive (typo in your previous comment) is a bug IMO, PS1 is not a bash-specific variable, it has no business unsetting it. It's the only shell that does that (thoughyashalso setsPS1to a default value even when non-interactive).
â Stéphane Chazelas
Aug 15 at 7:20
1
Since the code in question is in a bash-specific file, this seems like a reasonable answer. Other answers address the more-general case of POSIX specs or other shells. YouâÂÂve answered the âÂÂwhat is the purpose of this?â intention in the Question while appropriately leaving aside the rest. ItâÂÂs good to know what bash is doing and possibly better ways to accomplish the goal, too.
â Jeff Schaller
Aug 15 at 10:33
I would consider this answer more complete if it suggested a more reliable alternative (say,[[ $- = *i* ]] && source ~/.bash_profile).
â Charles Duffy
Aug 15 at 19:48
@CharlesDuffy Frankly I don't think there's much wrong with[ -n "$PS1" ], but I have still updated my answer to highlight that the bash manual also suggests/recommends inspecting$-to determine whether the shell is interactive, I hope you find that improves the answer. Cheers!
â Filipe Brandenburger
Aug 16 at 1:39
 |Â
show 2 more comments
bash, at least, will unset PS1 and PS2 if the shell is interactive. You can see that for yourself, with( export PS1='abc$ '; bash -c 'echo "[$PS1]"' ), which simply prints. It seems zsh does not do the same, at least from an experiment... In any case, the intention of the[ -n "$PS1" ]is to check whether the shell is interactive or not.
â Filipe Brandenburger
Aug 15 at 6:59
3
Thatbashunsets PS1 when non-interactive (typo in your previous comment) is a bug IMO, PS1 is not a bash-specific variable, it has no business unsetting it. It's the only shell that does that (thoughyashalso setsPS1to a default value even when non-interactive).
â Stéphane Chazelas
Aug 15 at 7:20
1
Since the code in question is in a bash-specific file, this seems like a reasonable answer. Other answers address the more-general case of POSIX specs or other shells. YouâÂÂve answered the âÂÂwhat is the purpose of this?â intention in the Question while appropriately leaving aside the rest. ItâÂÂs good to know what bash is doing and possibly better ways to accomplish the goal, too.
â Jeff Schaller
Aug 15 at 10:33
I would consider this answer more complete if it suggested a more reliable alternative (say,[[ $- = *i* ]] && source ~/.bash_profile).
â Charles Duffy
Aug 15 at 19:48
@CharlesDuffy Frankly I don't think there's much wrong with[ -n "$PS1" ], but I have still updated my answer to highlight that the bash manual also suggests/recommends inspecting$-to determine whether the shell is interactive, I hope you find that improves the answer. Cheers!
â Filipe Brandenburger
Aug 16 at 1:39
bash, at least, will unset PS1 and PS2 if the shell is interactive. You can see that for yourself, with
( export PS1='abc$ '; bash -c 'echo "[$PS1]"' ), which simply prints . It seems zsh does not do the same, at least from an experiment... In any case, the intention of the [ -n "$PS1" ] is to check whether the shell is interactive or not.â Filipe Brandenburger
Aug 15 at 6:59
bash, at least, will unset PS1 and PS2 if the shell is interactive. You can see that for yourself, with
( export PS1='abc$ '; bash -c 'echo "[$PS1]"' ), which simply prints . It seems zsh does not do the same, at least from an experiment... In any case, the intention of the [ -n "$PS1" ] is to check whether the shell is interactive or not.â Filipe Brandenburger
Aug 15 at 6:59
3
3
That
bash unsets PS1 when non-interactive (typo in your previous comment) is a bug IMO, PS1 is not a bash-specific variable, it has no business unsetting it. It's the only shell that does that (though yash also sets PS1 to a default value even when non-interactive).â Stéphane Chazelas
Aug 15 at 7:20
That
bash unsets PS1 when non-interactive (typo in your previous comment) is a bug IMO, PS1 is not a bash-specific variable, it has no business unsetting it. It's the only shell that does that (though yash also sets PS1 to a default value even when non-interactive).â Stéphane Chazelas
Aug 15 at 7:20
1
1
Since the code in question is in a bash-specific file, this seems like a reasonable answer. Other answers address the more-general case of POSIX specs or other shells. YouâÂÂve answered the âÂÂwhat is the purpose of this?â intention in the Question while appropriately leaving aside the rest. ItâÂÂs good to know what bash is doing and possibly better ways to accomplish the goal, too.
â Jeff Schaller
Aug 15 at 10:33
Since the code in question is in a bash-specific file, this seems like a reasonable answer. Other answers address the more-general case of POSIX specs or other shells. YouâÂÂve answered the âÂÂwhat is the purpose of this?â intention in the Question while appropriately leaving aside the rest. ItâÂÂs good to know what bash is doing and possibly better ways to accomplish the goal, too.
â Jeff Schaller
Aug 15 at 10:33
I would consider this answer more complete if it suggested a more reliable alternative (say,
[[ $- = *i* ]] && source ~/.bash_profile).â Charles Duffy
Aug 15 at 19:48
I would consider this answer more complete if it suggested a more reliable alternative (say,
[[ $- = *i* ]] && source ~/.bash_profile).â Charles Duffy
Aug 15 at 19:48
@CharlesDuffy Frankly I don't think there's much wrong with
[ -n "$PS1" ], but I have still updated my answer to highlight that the bash manual also suggests/recommends inspecting $- to determine whether the shell is interactive, I hope you find that improves the answer. Cheers!â Filipe Brandenburger
Aug 16 at 1:39
@CharlesDuffy Frankly I don't think there's much wrong with
[ -n "$PS1" ], but I have still updated my answer to highlight that the bash manual also suggests/recommends inspecting $- to determine whether the shell is interactive, I hope you find that improves the answer. Cheers!â Filipe Brandenburger
Aug 16 at 1:39
 |Â
show 2 more comments
up vote
19
down vote
What this does
This is a widespread way of testing whether the shell is interactive. Beware that it only works in bash, it doesn't work with other shells. So it's ok (if silly) for .bashrc, but it wouldn't work in .profile (which is read by sh, and bash is only one of the possible implementations of sh, and not the most common one).
Why it works (in bash only!)
An interactive shell sets the shell variable PS1 to the default prompt string. So if the shell is interactive, PS1 is set (unless the user's .bashrc has removed it, which can't have happened yet at the top of .bashrc, and you could consider that it's a silly thing to do anyway).
The converse is true in bash: non-interactive instances of bash unset PS1 when they start. Note that this behavior is specific to bash, and is arguably a bug (why would bash -c '⦠do stuff with $varâ¦' not work when var is PS1?). But all versions of bash up to and including 4.4 (the latest version as I write) do this.
Many systems export PS1 to the environment. It's a bad idea, because many different shells use PS1 but with a different syntax (e.g. bash's prompt escapes are completely different from zsh's prompt escapes). But it's widespread enough that in practice, seeing that PS1 is set is not a reliable indicator that the shell is interactive. The shell might have inherited PS1 from the environment.
Why it's (mis)used here
.bashrc is the file that bash reads at startup when it's interactive. A less well-known fact is that bash also reads .bashrc is a login shell and bash's heuristics conclude that this is a remote session (bash checks if its parent is rshd or sshd). In this second case, it's unlikely that PS1 would be set in the environment, because no dot file has run yet.
However, the way the code uses this information is counterproductive.
- If the shell is an interactive shell, then this runs
.bash_profilein that shell. But.bash_profileis a login-time script. It might run some programs that are intended to be run only once per session. It might override some environment variables that the user had deliberately set to a different value before running that shell. Running.bash_profilein a non-login shell is disruptive. - If the shell is a non-interactive remote login shell, it won't load
.bash_profile. But this is the case where loading.bash_profilecould be useful, because a non-interactive login shell doesn't automatically load/etc/profileand~/.profile.
I think the reason people do this is for users who log in through a GUI (a very common case) and who put their environment variable settings in .bash_profile rather than .profile. Most GUI login mechanisms invoke .profile but not .bash_profile (reading .bash_profile would require running bash as part of the session startup, instead of sh). With this configuration, when the user opens a terminal, they'll get their environment variables. However, the user will not get their environment variables in GUI applications, which is a very common source of confusion. The solution here is to use .profile instead of .bash_profile to set environment variables. Adding a bridge between .bashrc and .bash_profile creates more problems than it solves.
What to do instead
There's a straightforward, portable way of testing whether the current shell is interactive: test whether the option -i is enabled.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
This is useful in .bashrc to read .profile only if the shell is non-interactive âÂÂài.e. the opposite of what the code does! Read .profile if bash is a (non-interactive) login shell, and don't read it if it's an interactive shell.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
4
Might be worth noting that a better way to test if a shell is interactive is with[[ -o interactive ]](ksh, bash, zsh) orcase $- in (*i*) ...; esac(POSIX)
â Stéphane Chazelas
Aug 15 at 6:51
2
My bash (version 4.4.12) actually seems to unsetPS1if not run interactively. It is easy enough to test:PS1=cuckoo bash -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'will not print anything, whilePS1=cuckoo bash -i -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'prints the value of$PS1set in your bash startup files (it will not print the string "cuckoo").
â FooF
Aug 15 at 8:10
1
@Stéphane Chazelas: POSIX does not require that$-containsiwith an interactive shell.
â schily
Aug 15 at 9:20
1
Bosh does this since 2012 to be compatible to ksh. It just was not required by POSIX until the change you mantion becomes effective.
â schily
Aug 15 at 12:42
1
Frankly, I'd say calling[ -n "$PS1" ]wrong is going a bit too far, after all it only breaks when someone is exporting PS1 (which in your answer you say it's a bad idea and even go into the reasons why) and that doesn't affect bash anyways (since it unsets PS1 and PS2 if the shell is non-interactive.) Maybe using a word such as "discouraged" or talking about the "limitations" of the approach would have been better. I don't think it's "wrong" altogether. If anything is wrong is exporting PS1, that's for sure! Anyways, thanks for going into the details of this.
â Filipe Brandenburger
Aug 16 at 1:33
 |Â
show 3 more comments
up vote
19
down vote
What this does
This is a widespread way of testing whether the shell is interactive. Beware that it only works in bash, it doesn't work with other shells. So it's ok (if silly) for .bashrc, but it wouldn't work in .profile (which is read by sh, and bash is only one of the possible implementations of sh, and not the most common one).
Why it works (in bash only!)
An interactive shell sets the shell variable PS1 to the default prompt string. So if the shell is interactive, PS1 is set (unless the user's .bashrc has removed it, which can't have happened yet at the top of .bashrc, and you could consider that it's a silly thing to do anyway).
The converse is true in bash: non-interactive instances of bash unset PS1 when they start. Note that this behavior is specific to bash, and is arguably a bug (why would bash -c '⦠do stuff with $varâ¦' not work when var is PS1?). But all versions of bash up to and including 4.4 (the latest version as I write) do this.
Many systems export PS1 to the environment. It's a bad idea, because many different shells use PS1 but with a different syntax (e.g. bash's prompt escapes are completely different from zsh's prompt escapes). But it's widespread enough that in practice, seeing that PS1 is set is not a reliable indicator that the shell is interactive. The shell might have inherited PS1 from the environment.
Why it's (mis)used here
.bashrc is the file that bash reads at startup when it's interactive. A less well-known fact is that bash also reads .bashrc is a login shell and bash's heuristics conclude that this is a remote session (bash checks if its parent is rshd or sshd). In this second case, it's unlikely that PS1 would be set in the environment, because no dot file has run yet.
However, the way the code uses this information is counterproductive.
- If the shell is an interactive shell, then this runs
.bash_profilein that shell. But.bash_profileis a login-time script. It might run some programs that are intended to be run only once per session. It might override some environment variables that the user had deliberately set to a different value before running that shell. Running.bash_profilein a non-login shell is disruptive. - If the shell is a non-interactive remote login shell, it won't load
.bash_profile. But this is the case where loading.bash_profilecould be useful, because a non-interactive login shell doesn't automatically load/etc/profileand~/.profile.
I think the reason people do this is for users who log in through a GUI (a very common case) and who put their environment variable settings in .bash_profile rather than .profile. Most GUI login mechanisms invoke .profile but not .bash_profile (reading .bash_profile would require running bash as part of the session startup, instead of sh). With this configuration, when the user opens a terminal, they'll get their environment variables. However, the user will not get their environment variables in GUI applications, which is a very common source of confusion. The solution here is to use .profile instead of .bash_profile to set environment variables. Adding a bridge between .bashrc and .bash_profile creates more problems than it solves.
What to do instead
There's a straightforward, portable way of testing whether the current shell is interactive: test whether the option -i is enabled.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
This is useful in .bashrc to read .profile only if the shell is non-interactive âÂÂài.e. the opposite of what the code does! Read .profile if bash is a (non-interactive) login shell, and don't read it if it's an interactive shell.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
4
Might be worth noting that a better way to test if a shell is interactive is with[[ -o interactive ]](ksh, bash, zsh) orcase $- in (*i*) ...; esac(POSIX)
â Stéphane Chazelas
Aug 15 at 6:51
2
My bash (version 4.4.12) actually seems to unsetPS1if not run interactively. It is easy enough to test:PS1=cuckoo bash -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'will not print anything, whilePS1=cuckoo bash -i -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'prints the value of$PS1set in your bash startup files (it will not print the string "cuckoo").
â FooF
Aug 15 at 8:10
1
@Stéphane Chazelas: POSIX does not require that$-containsiwith an interactive shell.
â schily
Aug 15 at 9:20
1
Bosh does this since 2012 to be compatible to ksh. It just was not required by POSIX until the change you mantion becomes effective.
â schily
Aug 15 at 12:42
1
Frankly, I'd say calling[ -n "$PS1" ]wrong is going a bit too far, after all it only breaks when someone is exporting PS1 (which in your answer you say it's a bad idea and even go into the reasons why) and that doesn't affect bash anyways (since it unsets PS1 and PS2 if the shell is non-interactive.) Maybe using a word such as "discouraged" or talking about the "limitations" of the approach would have been better. I don't think it's "wrong" altogether. If anything is wrong is exporting PS1, that's for sure! Anyways, thanks for going into the details of this.
â Filipe Brandenburger
Aug 16 at 1:33
 |Â
show 3 more comments
up vote
19
down vote
up vote
19
down vote
What this does
This is a widespread way of testing whether the shell is interactive. Beware that it only works in bash, it doesn't work with other shells. So it's ok (if silly) for .bashrc, but it wouldn't work in .profile (which is read by sh, and bash is only one of the possible implementations of sh, and not the most common one).
Why it works (in bash only!)
An interactive shell sets the shell variable PS1 to the default prompt string. So if the shell is interactive, PS1 is set (unless the user's .bashrc has removed it, which can't have happened yet at the top of .bashrc, and you could consider that it's a silly thing to do anyway).
The converse is true in bash: non-interactive instances of bash unset PS1 when they start. Note that this behavior is specific to bash, and is arguably a bug (why would bash -c '⦠do stuff with $varâ¦' not work when var is PS1?). But all versions of bash up to and including 4.4 (the latest version as I write) do this.
Many systems export PS1 to the environment. It's a bad idea, because many different shells use PS1 but with a different syntax (e.g. bash's prompt escapes are completely different from zsh's prompt escapes). But it's widespread enough that in practice, seeing that PS1 is set is not a reliable indicator that the shell is interactive. The shell might have inherited PS1 from the environment.
Why it's (mis)used here
.bashrc is the file that bash reads at startup when it's interactive. A less well-known fact is that bash also reads .bashrc is a login shell and bash's heuristics conclude that this is a remote session (bash checks if its parent is rshd or sshd). In this second case, it's unlikely that PS1 would be set in the environment, because no dot file has run yet.
However, the way the code uses this information is counterproductive.
- If the shell is an interactive shell, then this runs
.bash_profilein that shell. But.bash_profileis a login-time script. It might run some programs that are intended to be run only once per session. It might override some environment variables that the user had deliberately set to a different value before running that shell. Running.bash_profilein a non-login shell is disruptive. - If the shell is a non-interactive remote login shell, it won't load
.bash_profile. But this is the case where loading.bash_profilecould be useful, because a non-interactive login shell doesn't automatically load/etc/profileand~/.profile.
I think the reason people do this is for users who log in through a GUI (a very common case) and who put their environment variable settings in .bash_profile rather than .profile. Most GUI login mechanisms invoke .profile but not .bash_profile (reading .bash_profile would require running bash as part of the session startup, instead of sh). With this configuration, when the user opens a terminal, they'll get their environment variables. However, the user will not get their environment variables in GUI applications, which is a very common source of confusion. The solution here is to use .profile instead of .bash_profile to set environment variables. Adding a bridge between .bashrc and .bash_profile creates more problems than it solves.
What to do instead
There's a straightforward, portable way of testing whether the current shell is interactive: test whether the option -i is enabled.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
This is useful in .bashrc to read .profile only if the shell is non-interactive âÂÂài.e. the opposite of what the code does! Read .profile if bash is a (non-interactive) login shell, and don't read it if it's an interactive shell.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
What this does
This is a widespread way of testing whether the shell is interactive. Beware that it only works in bash, it doesn't work with other shells. So it's ok (if silly) for .bashrc, but it wouldn't work in .profile (which is read by sh, and bash is only one of the possible implementations of sh, and not the most common one).
Why it works (in bash only!)
An interactive shell sets the shell variable PS1 to the default prompt string. So if the shell is interactive, PS1 is set (unless the user's .bashrc has removed it, which can't have happened yet at the top of .bashrc, and you could consider that it's a silly thing to do anyway).
The converse is true in bash: non-interactive instances of bash unset PS1 when they start. Note that this behavior is specific to bash, and is arguably a bug (why would bash -c '⦠do stuff with $varâ¦' not work when var is PS1?). But all versions of bash up to and including 4.4 (the latest version as I write) do this.
Many systems export PS1 to the environment. It's a bad idea, because many different shells use PS1 but with a different syntax (e.g. bash's prompt escapes are completely different from zsh's prompt escapes). But it's widespread enough that in practice, seeing that PS1 is set is not a reliable indicator that the shell is interactive. The shell might have inherited PS1 from the environment.
Why it's (mis)used here
.bashrc is the file that bash reads at startup when it's interactive. A less well-known fact is that bash also reads .bashrc is a login shell and bash's heuristics conclude that this is a remote session (bash checks if its parent is rshd or sshd). In this second case, it's unlikely that PS1 would be set in the environment, because no dot file has run yet.
However, the way the code uses this information is counterproductive.
- If the shell is an interactive shell, then this runs
.bash_profilein that shell. But.bash_profileis a login-time script. It might run some programs that are intended to be run only once per session. It might override some environment variables that the user had deliberately set to a different value before running that shell. Running.bash_profilein a non-login shell is disruptive. - If the shell is a non-interactive remote login shell, it won't load
.bash_profile. But this is the case where loading.bash_profilecould be useful, because a non-interactive login shell doesn't automatically load/etc/profileand~/.profile.
I think the reason people do this is for users who log in through a GUI (a very common case) and who put their environment variable settings in .bash_profile rather than .profile. Most GUI login mechanisms invoke .profile but not .bash_profile (reading .bash_profile would require running bash as part of the session startup, instead of sh). With this configuration, when the user opens a terminal, they'll get their environment variables. However, the user will not get their environment variables in GUI applications, which is a very common source of confusion. The solution here is to use .profile instead of .bash_profile to set environment variables. Adding a bridge between .bashrc and .bash_profile creates more problems than it solves.
What to do instead
There's a straightforward, portable way of testing whether the current shell is interactive: test whether the option -i is enabled.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
This is useful in .bashrc to read .profile only if the shell is non-interactive âÂÂài.e. the opposite of what the code does! Read .profile if bash is a (non-interactive) login shell, and don't read it if it's an interactive shell.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
edited Aug 16 at 20:58
answered Aug 15 at 6:31
Gilles
509k12010061536
509k12010061536
4
Might be worth noting that a better way to test if a shell is interactive is with[[ -o interactive ]](ksh, bash, zsh) orcase $- in (*i*) ...; esac(POSIX)
â Stéphane Chazelas
Aug 15 at 6:51
2
My bash (version 4.4.12) actually seems to unsetPS1if not run interactively. It is easy enough to test:PS1=cuckoo bash -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'will not print anything, whilePS1=cuckoo bash -i -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'prints the value of$PS1set in your bash startup files (it will not print the string "cuckoo").
â FooF
Aug 15 at 8:10
1
@Stéphane Chazelas: POSIX does not require that$-containsiwith an interactive shell.
â schily
Aug 15 at 9:20
1
Bosh does this since 2012 to be compatible to ksh. It just was not required by POSIX until the change you mantion becomes effective.
â schily
Aug 15 at 12:42
1
Frankly, I'd say calling[ -n "$PS1" ]wrong is going a bit too far, after all it only breaks when someone is exporting PS1 (which in your answer you say it's a bad idea and even go into the reasons why) and that doesn't affect bash anyways (since it unsets PS1 and PS2 if the shell is non-interactive.) Maybe using a word such as "discouraged" or talking about the "limitations" of the approach would have been better. I don't think it's "wrong" altogether. If anything is wrong is exporting PS1, that's for sure! Anyways, thanks for going into the details of this.
â Filipe Brandenburger
Aug 16 at 1:33
 |Â
show 3 more comments
4
Might be worth noting that a better way to test if a shell is interactive is with[[ -o interactive ]](ksh, bash, zsh) orcase $- in (*i*) ...; esac(POSIX)
â Stéphane Chazelas
Aug 15 at 6:51
2
My bash (version 4.4.12) actually seems to unsetPS1if not run interactively. It is easy enough to test:PS1=cuckoo bash -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'will not print anything, whilePS1=cuckoo bash -i -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"'prints the value of$PS1set in your bash startup files (it will not print the string "cuckoo").
â FooF
Aug 15 at 8:10
1
@Stéphane Chazelas: POSIX does not require that$-containsiwith an interactive shell.
â schily
Aug 15 at 9:20
1
Bosh does this since 2012 to be compatible to ksh. It just was not required by POSIX until the change you mantion becomes effective.
â schily
Aug 15 at 12:42
1
Frankly, I'd say calling[ -n "$PS1" ]wrong is going a bit too far, after all it only breaks when someone is exporting PS1 (which in your answer you say it's a bad idea and even go into the reasons why) and that doesn't affect bash anyways (since it unsets PS1 and PS2 if the shell is non-interactive.) Maybe using a word such as "discouraged" or talking about the "limitations" of the approach would have been better. I don't think it's "wrong" altogether. If anything is wrong is exporting PS1, that's for sure! Anyways, thanks for going into the details of this.
â Filipe Brandenburger
Aug 16 at 1:33
4
4
Might be worth noting that a better way to test if a shell is interactive is with
[[ -o interactive ]] (ksh, bash, zsh) or case $- in (*i*) ...; esac (POSIX)â Stéphane Chazelas
Aug 15 at 6:51
Might be worth noting that a better way to test if a shell is interactive is with
[[ -o interactive ]] (ksh, bash, zsh) or case $- in (*i*) ...; esac (POSIX)â Stéphane Chazelas
Aug 15 at 6:51
2
2
My bash (version 4.4.12) actually seems to unset
PS1 if not run interactively. It is easy enough to test: PS1=cuckoo bash -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"' will not print anything, while PS1=cuckoo bash -i -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"' prints the value of $PS1 set in your bash startup files (it will not print the string "cuckoo").â FooF
Aug 15 at 8:10
My bash (version 4.4.12) actually seems to unset
PS1 if not run interactively. It is easy enough to test: PS1=cuckoo bash -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"' will not print anything, while PS1=cuckoo bash -i -c '[ -n "$PS1" ] && echo "PS1=[$PS1]"' prints the value of $PS1 set in your bash startup files (it will not print the string "cuckoo").â FooF
Aug 15 at 8:10
1
1
@Stéphane Chazelas: POSIX does not require that
$- contains i with an interactive shell.â schily
Aug 15 at 9:20
@Stéphane Chazelas: POSIX does not require that
$- contains i with an interactive shell.â schily
Aug 15 at 9:20
1
1
Bosh does this since 2012 to be compatible to ksh. It just was not required by POSIX until the change you mantion becomes effective.
â schily
Aug 15 at 12:42
Bosh does this since 2012 to be compatible to ksh. It just was not required by POSIX until the change you mantion becomes effective.
â schily
Aug 15 at 12:42
1
1
Frankly, I'd say calling
[ -n "$PS1" ] wrong is going a bit too far, after all it only breaks when someone is exporting PS1 (which in your answer you say it's a bad idea and even go into the reasons why) and that doesn't affect bash anyways (since it unsets PS1 and PS2 if the shell is non-interactive.) Maybe using a word such as "discouraged" or talking about the "limitations" of the approach would have been better. I don't think it's "wrong" altogether. If anything is wrong is exporting PS1, that's for sure! Anyways, thanks for going into the details of this.â Filipe Brandenburger
Aug 16 at 1:33
Frankly, I'd say calling
[ -n "$PS1" ] wrong is going a bit too far, after all it only breaks when someone is exporting PS1 (which in your answer you say it's a bad idea and even go into the reasons why) and that doesn't affect bash anyways (since it unsets PS1 and PS2 if the shell is non-interactive.) Maybe using a word such as "discouraged" or talking about the "limitations" of the approach would have been better. I don't think it's "wrong" altogether. If anything is wrong is exporting PS1, that's for sure! Anyways, thanks for going into the details of this.â Filipe Brandenburger
Aug 16 at 1:33
 |Â
show 3 more comments
up vote
1
down vote
It seems that this strange concept is a result from the fact that bash did not start as a POSIX shell clone but as a Bourne Shell clone.
As a result, the POSIX interactive behavior ($ENV gets called for interactive shells) has been added later to bash and is not widely known.
There is one shell that grants similar behavior. This is csh and csh grants that $prompt has specific values:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
But this neither applies to the Bourne Shell nor to POSIX shells.
For a POSIX shell, the only granted method is to put code for interactive shells into the file:
$ENV
that has a shell specific name. It is e.g.
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Other people mentioned the shell flag -i, but this is not usable for reliable programming. POSIX neither requires that set -i works, nor that $- contains an i for interactive shells. POSIX just requires that sh -i enforces the shell into the interactive mode.
Since the variable $PS1 can be imported from the environment, it may have a value even in non-interactive mode. The fact that bash unsets PS1 in any non-interactive shell is not granted by the standard and not done by any other shell.
So clean programming (even with bash) is to put the commands for interactive shells into $HOME/.bashrc.
add a comment |Â
up vote
1
down vote
It seems that this strange concept is a result from the fact that bash did not start as a POSIX shell clone but as a Bourne Shell clone.
As a result, the POSIX interactive behavior ($ENV gets called for interactive shells) has been added later to bash and is not widely known.
There is one shell that grants similar behavior. This is csh and csh grants that $prompt has specific values:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
But this neither applies to the Bourne Shell nor to POSIX shells.
For a POSIX shell, the only granted method is to put code for interactive shells into the file:
$ENV
that has a shell specific name. It is e.g.
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Other people mentioned the shell flag -i, but this is not usable for reliable programming. POSIX neither requires that set -i works, nor that $- contains an i for interactive shells. POSIX just requires that sh -i enforces the shell into the interactive mode.
Since the variable $PS1 can be imported from the environment, it may have a value even in non-interactive mode. The fact that bash unsets PS1 in any non-interactive shell is not granted by the standard and not done by any other shell.
So clean programming (even with bash) is to put the commands for interactive shells into $HOME/.bashrc.
add a comment |Â
up vote
1
down vote
up vote
1
down vote
It seems that this strange concept is a result from the fact that bash did not start as a POSIX shell clone but as a Bourne Shell clone.
As a result, the POSIX interactive behavior ($ENV gets called for interactive shells) has been added later to bash and is not widely known.
There is one shell that grants similar behavior. This is csh and csh grants that $prompt has specific values:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
But this neither applies to the Bourne Shell nor to POSIX shells.
For a POSIX shell, the only granted method is to put code for interactive shells into the file:
$ENV
that has a shell specific name. It is e.g.
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Other people mentioned the shell flag -i, but this is not usable for reliable programming. POSIX neither requires that set -i works, nor that $- contains an i for interactive shells. POSIX just requires that sh -i enforces the shell into the interactive mode.
Since the variable $PS1 can be imported from the environment, it may have a value even in non-interactive mode. The fact that bash unsets PS1 in any non-interactive shell is not granted by the standard and not done by any other shell.
So clean programming (even with bash) is to put the commands for interactive shells into $HOME/.bashrc.
It seems that this strange concept is a result from the fact that bash did not start as a POSIX shell clone but as a Bourne Shell clone.
As a result, the POSIX interactive behavior ($ENV gets called for interactive shells) has been added later to bash and is not widely known.
There is one shell that grants similar behavior. This is csh and csh grants that $prompt has specific values:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
But this neither applies to the Bourne Shell nor to POSIX shells.
For a POSIX shell, the only granted method is to put code for interactive shells into the file:
$ENV
that has a shell specific name. It is e.g.
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Other people mentioned the shell flag -i, but this is not usable for reliable programming. POSIX neither requires that set -i works, nor that $- contains an i for interactive shells. POSIX just requires that sh -i enforces the shell into the interactive mode.
Since the variable $PS1 can be imported from the environment, it may have a value even in non-interactive mode. The fact that bash unsets PS1 in any non-interactive shell is not granted by the standard and not done by any other shell.
So clean programming (even with bash) is to put the commands for interactive shells into $HOME/.bashrc.
answered Aug 15 at 9:41
schily
9,63131437
9,63131437
add a comment |Â
add a comment |Â
up vote
0
down vote
I am going first to talk of what Debian, and most of the time also Ubuntu sets for bash. And latter touch on other systems.
In the setting of shell start files there is a lot of opinion.
I also have my opinion but I will try to show existing examples of correct settings.
I'll use debuan as it is quite easy to find examples of its files.
And debian is heavily used, so the settings have been well tested,
What is the goal of checking that PS1 is set?
Only to find out if the shell is interactive.
The default /etc/profile in debian and ubuntu (from /usr/share/base-files/profile):
if [ "$PS1-" ]; then
if [ "$BASH-" ] && [ "$BASH" != "/bin/sh" ]; then
The if's read: if interactive (PS1 default set) and it is a bash shell (but not acting as a default sh) then change PS1 to a particular new one (not the default one).
The default /etc/bash.bashrc in debian also contains:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Which is pretty clear in what it does: If interactive don't source (the rest).
However, in /etc/skel/.bashrc is an example of the correct way to test for an interactive shell (using $-):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
That should show clearly the why of PS1 and one alternative.
The correct order
The setting you are reporting should be avoided.
The order (from system settings to more specific user settings (for bash)) is /etc/profile, /etc/bash.bashrc, ~/.profile and finally ~/.bashrc. That places the most broad effects (and for more shells) in /etc/profile (which is owned by root) followed by /etc/bash.bashrc (which is also owned by root) but only affects bash. Then come the personal settings in $HOME, the first is ~/.profile for most shells and ~/.bashrc (almost equivalent to ~/.bash_profile), specific for bash only.
It is therefore wrong to source ~/.bashrc in ~/.profile, it is transforming an specific user setting for bash to a more general that is affecting more shells. Except if done in this way:
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
It checks that bash is running and only load .bashrc if that is the case.
This is an upstream decision coming from Debian. The rationale is explained here.
In fact, the reverse, sourcing ~/.profile in ~/.bash_profile (or ~/.bashrc) is only re-applying general rules that should had been loaded already to a particular use case, and therefore "not that bad" (I am not saying "good"). And I am not saying good because it may cause the sourcing of files to loop. Like when a sub-directory loads a parent, that is a directory loop.
And is in this cross sourcing that the check for interactive shell makes sense. Only when a shell is interactive is ~/.bashrc loaded, but it in turn may be loading ~/.profile (or the other way around) and is in this case that checking for an interactive shell could be used.
add a comment |Â
up vote
0
down vote
I am going first to talk of what Debian, and most of the time also Ubuntu sets for bash. And latter touch on other systems.
In the setting of shell start files there is a lot of opinion.
I also have my opinion but I will try to show existing examples of correct settings.
I'll use debuan as it is quite easy to find examples of its files.
And debian is heavily used, so the settings have been well tested,
What is the goal of checking that PS1 is set?
Only to find out if the shell is interactive.
The default /etc/profile in debian and ubuntu (from /usr/share/base-files/profile):
if [ "$PS1-" ]; then
if [ "$BASH-" ] && [ "$BASH" != "/bin/sh" ]; then
The if's read: if interactive (PS1 default set) and it is a bash shell (but not acting as a default sh) then change PS1 to a particular new one (not the default one).
The default /etc/bash.bashrc in debian also contains:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Which is pretty clear in what it does: If interactive don't source (the rest).
However, in /etc/skel/.bashrc is an example of the correct way to test for an interactive shell (using $-):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
That should show clearly the why of PS1 and one alternative.
The correct order
The setting you are reporting should be avoided.
The order (from system settings to more specific user settings (for bash)) is /etc/profile, /etc/bash.bashrc, ~/.profile and finally ~/.bashrc. That places the most broad effects (and for more shells) in /etc/profile (which is owned by root) followed by /etc/bash.bashrc (which is also owned by root) but only affects bash. Then come the personal settings in $HOME, the first is ~/.profile for most shells and ~/.bashrc (almost equivalent to ~/.bash_profile), specific for bash only.
It is therefore wrong to source ~/.bashrc in ~/.profile, it is transforming an specific user setting for bash to a more general that is affecting more shells. Except if done in this way:
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
It checks that bash is running and only load .bashrc if that is the case.
This is an upstream decision coming from Debian. The rationale is explained here.
In fact, the reverse, sourcing ~/.profile in ~/.bash_profile (or ~/.bashrc) is only re-applying general rules that should had been loaded already to a particular use case, and therefore "not that bad" (I am not saying "good"). And I am not saying good because it may cause the sourcing of files to loop. Like when a sub-directory loads a parent, that is a directory loop.
And is in this cross sourcing that the check for interactive shell makes sense. Only when a shell is interactive is ~/.bashrc loaded, but it in turn may be loading ~/.profile (or the other way around) and is in this case that checking for an interactive shell could be used.
add a comment |Â
up vote
0
down vote
up vote
0
down vote
I am going first to talk of what Debian, and most of the time also Ubuntu sets for bash. And latter touch on other systems.
In the setting of shell start files there is a lot of opinion.
I also have my opinion but I will try to show existing examples of correct settings.
I'll use debuan as it is quite easy to find examples of its files.
And debian is heavily used, so the settings have been well tested,
What is the goal of checking that PS1 is set?
Only to find out if the shell is interactive.
The default /etc/profile in debian and ubuntu (from /usr/share/base-files/profile):
if [ "$PS1-" ]; then
if [ "$BASH-" ] && [ "$BASH" != "/bin/sh" ]; then
The if's read: if interactive (PS1 default set) and it is a bash shell (but not acting as a default sh) then change PS1 to a particular new one (not the default one).
The default /etc/bash.bashrc in debian also contains:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Which is pretty clear in what it does: If interactive don't source (the rest).
However, in /etc/skel/.bashrc is an example of the correct way to test for an interactive shell (using $-):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
That should show clearly the why of PS1 and one alternative.
The correct order
The setting you are reporting should be avoided.
The order (from system settings to more specific user settings (for bash)) is /etc/profile, /etc/bash.bashrc, ~/.profile and finally ~/.bashrc. That places the most broad effects (and for more shells) in /etc/profile (which is owned by root) followed by /etc/bash.bashrc (which is also owned by root) but only affects bash. Then come the personal settings in $HOME, the first is ~/.profile for most shells and ~/.bashrc (almost equivalent to ~/.bash_profile), specific for bash only.
It is therefore wrong to source ~/.bashrc in ~/.profile, it is transforming an specific user setting for bash to a more general that is affecting more shells. Except if done in this way:
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
It checks that bash is running and only load .bashrc if that is the case.
This is an upstream decision coming from Debian. The rationale is explained here.
In fact, the reverse, sourcing ~/.profile in ~/.bash_profile (or ~/.bashrc) is only re-applying general rules that should had been loaded already to a particular use case, and therefore "not that bad" (I am not saying "good"). And I am not saying good because it may cause the sourcing of files to loop. Like when a sub-directory loads a parent, that is a directory loop.
And is in this cross sourcing that the check for interactive shell makes sense. Only when a shell is interactive is ~/.bashrc loaded, but it in turn may be loading ~/.profile (or the other way around) and is in this case that checking for an interactive shell could be used.
I am going first to talk of what Debian, and most of the time also Ubuntu sets for bash. And latter touch on other systems.
In the setting of shell start files there is a lot of opinion.
I also have my opinion but I will try to show existing examples of correct settings.
I'll use debuan as it is quite easy to find examples of its files.
And debian is heavily used, so the settings have been well tested,
What is the goal of checking that PS1 is set?
Only to find out if the shell is interactive.
The default /etc/profile in debian and ubuntu (from /usr/share/base-files/profile):
if [ "$PS1-" ]; then
if [ "$BASH-" ] && [ "$BASH" != "/bin/sh" ]; then
The if's read: if interactive (PS1 default set) and it is a bash shell (but not acting as a default sh) then change PS1 to a particular new one (not the default one).
The default /etc/bash.bashrc in debian also contains:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Which is pretty clear in what it does: If interactive don't source (the rest).
However, in /etc/skel/.bashrc is an example of the correct way to test for an interactive shell (using $-):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
That should show clearly the why of PS1 and one alternative.
The correct order
The setting you are reporting should be avoided.
The order (from system settings to more specific user settings (for bash)) is /etc/profile, /etc/bash.bashrc, ~/.profile and finally ~/.bashrc. That places the most broad effects (and for more shells) in /etc/profile (which is owned by root) followed by /etc/bash.bashrc (which is also owned by root) but only affects bash. Then come the personal settings in $HOME, the first is ~/.profile for most shells and ~/.bashrc (almost equivalent to ~/.bash_profile), specific for bash only.
It is therefore wrong to source ~/.bashrc in ~/.profile, it is transforming an specific user setting for bash to a more general that is affecting more shells. Except if done in this way:
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
It checks that bash is running and only load .bashrc if that is the case.
This is an upstream decision coming from Debian. The rationale is explained here.
In fact, the reverse, sourcing ~/.profile in ~/.bash_profile (or ~/.bashrc) is only re-applying general rules that should had been loaded already to a particular use case, and therefore "not that bad" (I am not saying "good"). And I am not saying good because it may cause the sourcing of files to loop. Like when a sub-directory loads a parent, that is a directory loop.
And is in this cross sourcing that the check for interactive shell makes sense. Only when a shell is interactive is ~/.bashrc loaded, but it in turn may be loading ~/.profile (or the other way around) and is in this case that checking for an interactive shell could be used.
answered Aug 18 at 3:31
Isaac
7,1061834
7,1061834
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f462663%2fpurpose-of-n-ps1-in-bashrc%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password