Purpose of [ -n “$PS1” ] in bashrc

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
10
down vote

favorite
2












What purpose does the [ -n "$PS1" ] in [ -n "$PS1" ] && source ~/.bash_profile; serve? This line is included in a .bashrc of a dotfiles repo.










share|improve this question



























    up vote
    10
    down vote

    favorite
    2












    What purpose does the [ -n "$PS1" ] in [ -n "$PS1" ] && source ~/.bash_profile; serve? This line is included in a .bashrc of a dotfiles repo.










    share|improve this question

























      up vote
      10
      down vote

      favorite
      2









      up vote
      10
      down vote

      favorite
      2






      2





      What purpose does the [ -n "$PS1" ] in [ -n "$PS1" ] && source ~/.bash_profile; serve? This line is included in a .bashrc of a dotfiles repo.










      share|improve this question















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Aug 15 at 5:05









      msp9011

      3,46643862




      3,46643862










      asked Aug 15 at 4:40









      shotes

      594




      594




















          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.)






          share|improve this answer






















          • 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




            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




            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

















          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_profile in that shell. But .bash_profile is 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_profile in 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_profile could be useful, because a non-interactive login shell doesn't automatically load /etc/profile and ~/.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





          share|improve this answer


















          • 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






          • 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







          • 1




            @Stéphane Chazelas: POSIX does not require that $- contains i with 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

















          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.






          share|improve this answer



























            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.






            share|improve this answer




















              Your Answer







              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "106"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              convertImagesToLinks: false,
              noModals: false,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













               

              draft saved


              draft discarded


















              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






























              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.)






              share|improve this answer






















              • 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




                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




                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














              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.)






              share|improve this answer






















              • 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




                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




                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












              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.)






              share|improve this answer














              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.)







              share|improve this answer














              share|improve this answer



              share|improve this answer








              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




                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




                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






              • 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







              • 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












              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_profile in that shell. But .bash_profile is 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_profile in 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_profile could be useful, because a non-interactive login shell doesn't automatically load /etc/profile and ~/.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





              share|improve this answer


















              • 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






              • 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







              • 1




                @Stéphane Chazelas: POSIX does not require that $- contains i with 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














              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_profile in that shell. But .bash_profile is 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_profile in 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_profile could be useful, because a non-interactive login shell doesn't automatically load /etc/profile and ~/.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





              share|improve this answer


















              • 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






              • 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







              • 1




                @Stéphane Chazelas: POSIX does not require that $- contains i with 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












              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_profile in that shell. But .bash_profile is 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_profile in 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_profile could be useful, because a non-interactive login shell doesn't automatically load /etc/profile and ~/.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





              share|improve this answer














              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_profile in that shell. But .bash_profile is 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_profile in 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_profile could be useful, because a non-interactive login shell doesn't automatically load /etc/profile and ~/.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






              share|improve this answer














              share|improve this answer



              share|improve this answer








              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) or case $- in (*i*) ...; esac (POSIX)
                – Stéphane Chazelas
                Aug 15 at 6:51






              • 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







              • 1




                @Stéphane Chazelas: POSIX does not require that $- contains i with 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




                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




                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




                @Stéphane Chazelas: POSIX does not require that $- contains i with 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










              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.






              share|improve this answer
























                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.






                share|improve this answer






















                  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.






                  share|improve this answer












                  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.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Aug 15 at 9:41









                  schily

                  9,63131437




                  9,63131437




















                      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.






                      share|improve this answer
























                        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.






                        share|improve this answer






















                          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.






                          share|improve this answer












                          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.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Aug 18 at 3:31









                          Isaac

                          7,1061834




                          7,1061834



























                               

                              draft saved


                              draft discarded















































                               


                              draft saved


                              draft discarded














                              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













































































                              Popular posts from this blog

                              Peggy Mitchell

                              Palaiologos

                              The Forum (Inglewood, California)