How to export functions from .profile during graphical login












2















I am using Ubuntu 18.04 with GDM. I am trying to export some bash functions from my .profile.



As explained in this very good resource, the main difference between .bashrc and .profile is that the latter is executed only on login shells.



I am already successfully using .profile to export some env variables that would be not appropriate in .bashrc. Therefore, I know that .profile is being successfully sourced even on graphical login shells. For example, my $PATH definition looks something like this:



export PATH="something/bin:$PATH"


Had I put this in .bashrc, "something/bin" would get inserted again every time I run a subshell:



$ echo $PATH
something/bin:/usr/local/bin:/usr/bin:/bin
$ bash
$ echo $PATH
something/bin:something/bin:/usr/local/bin:/usr/bin:/bin


However, exporting a function like the following does not seem to work for graphical logins:



hello () { echo "hello"; }
export -f hello


It works correctly both when doing bash -l and from a console login.



So, the question is: why, if apparently .profile gets sourced (env vars are successfully exported, and it seems to be explicitly sourced in /etc/gdm3/Xsession) then exporting functions does not work?










share|improve this question


















  • 1





    What shell sources .profile though? There are a few ordinary shells will read the file when invoked as a login shell. Do you know for a fact that GDM starts a bash login shell, and not a sh login shell?

    – Kusalananda
    9 hours ago













  • No, I do not know for sure. I guess at least some of my assumptions are wrong, otherwise, this should work (unless it is a bug). However, my login shell is bash (specified in /etc/passwd) and the shebang of /etc/gdm3/Xsession is #!/bin/bash. I also confirmed that bash is being used to source .profile by printing $BASH_VERSION to a file.

    – tyrion
    9 hours ago











  • Ok, so bash reads the file. Good. The next thing to note is that an exported function is likely only usable in a bash shell child process. I've just tested exporting a function, starting another (non-bash) shell, and the function is not there. Nor is it there if I start bash from that other shell. It is there if I start a bash shell from the first shell. This means that if you start an interactive bash shell from something that is not bash, the function may not be in the environment.

    – Kusalananda
    9 hours ago






  • 2





    I suspect this may be a manifestation of this question's issue: an intervening dash (or sh, on Ubuntu), or system(), will strip out the exported functions' environment variables.

    – Michael Homer
    9 hours ago











  • @tyrion if you're running gnome, notice that the gnome-session script has a /bin/sh shebang, which means that it will be run with dash, which will wipe off all funny environment variables, as described in Michael Homer's comment. You may change that shebang by hand to #! /bin/bash (not really recommended), but it will be changed back at the next upgrade of the gnome-session-bin package.

    – mosvy
    4 hours ago


















2















I am using Ubuntu 18.04 with GDM. I am trying to export some bash functions from my .profile.



As explained in this very good resource, the main difference between .bashrc and .profile is that the latter is executed only on login shells.



I am already successfully using .profile to export some env variables that would be not appropriate in .bashrc. Therefore, I know that .profile is being successfully sourced even on graphical login shells. For example, my $PATH definition looks something like this:



export PATH="something/bin:$PATH"


Had I put this in .bashrc, "something/bin" would get inserted again every time I run a subshell:



$ echo $PATH
something/bin:/usr/local/bin:/usr/bin:/bin
$ bash
$ echo $PATH
something/bin:something/bin:/usr/local/bin:/usr/bin:/bin


However, exporting a function like the following does not seem to work for graphical logins:



hello () { echo "hello"; }
export -f hello


It works correctly both when doing bash -l and from a console login.



So, the question is: why, if apparently .profile gets sourced (env vars are successfully exported, and it seems to be explicitly sourced in /etc/gdm3/Xsession) then exporting functions does not work?










share|improve this question


















  • 1





    What shell sources .profile though? There are a few ordinary shells will read the file when invoked as a login shell. Do you know for a fact that GDM starts a bash login shell, and not a sh login shell?

    – Kusalananda
    9 hours ago













  • No, I do not know for sure. I guess at least some of my assumptions are wrong, otherwise, this should work (unless it is a bug). However, my login shell is bash (specified in /etc/passwd) and the shebang of /etc/gdm3/Xsession is #!/bin/bash. I also confirmed that bash is being used to source .profile by printing $BASH_VERSION to a file.

    – tyrion
    9 hours ago











  • Ok, so bash reads the file. Good. The next thing to note is that an exported function is likely only usable in a bash shell child process. I've just tested exporting a function, starting another (non-bash) shell, and the function is not there. Nor is it there if I start bash from that other shell. It is there if I start a bash shell from the first shell. This means that if you start an interactive bash shell from something that is not bash, the function may not be in the environment.

    – Kusalananda
    9 hours ago






  • 2





    I suspect this may be a manifestation of this question's issue: an intervening dash (or sh, on Ubuntu), or system(), will strip out the exported functions' environment variables.

    – Michael Homer
    9 hours ago











  • @tyrion if you're running gnome, notice that the gnome-session script has a /bin/sh shebang, which means that it will be run with dash, which will wipe off all funny environment variables, as described in Michael Homer's comment. You may change that shebang by hand to #! /bin/bash (not really recommended), but it will be changed back at the next upgrade of the gnome-session-bin package.

    – mosvy
    4 hours ago
















2












2








2








I am using Ubuntu 18.04 with GDM. I am trying to export some bash functions from my .profile.



As explained in this very good resource, the main difference between .bashrc and .profile is that the latter is executed only on login shells.



I am already successfully using .profile to export some env variables that would be not appropriate in .bashrc. Therefore, I know that .profile is being successfully sourced even on graphical login shells. For example, my $PATH definition looks something like this:



export PATH="something/bin:$PATH"


Had I put this in .bashrc, "something/bin" would get inserted again every time I run a subshell:



$ echo $PATH
something/bin:/usr/local/bin:/usr/bin:/bin
$ bash
$ echo $PATH
something/bin:something/bin:/usr/local/bin:/usr/bin:/bin


However, exporting a function like the following does not seem to work for graphical logins:



hello () { echo "hello"; }
export -f hello


It works correctly both when doing bash -l and from a console login.



So, the question is: why, if apparently .profile gets sourced (env vars are successfully exported, and it seems to be explicitly sourced in /etc/gdm3/Xsession) then exporting functions does not work?










share|improve this question














I am using Ubuntu 18.04 with GDM. I am trying to export some bash functions from my .profile.



As explained in this very good resource, the main difference between .bashrc and .profile is that the latter is executed only on login shells.



I am already successfully using .profile to export some env variables that would be not appropriate in .bashrc. Therefore, I know that .profile is being successfully sourced even on graphical login shells. For example, my $PATH definition looks something like this:



export PATH="something/bin:$PATH"


Had I put this in .bashrc, "something/bin" would get inserted again every time I run a subshell:



$ echo $PATH
something/bin:/usr/local/bin:/usr/bin:/bin
$ bash
$ echo $PATH
something/bin:something/bin:/usr/local/bin:/usr/bin:/bin


However, exporting a function like the following does not seem to work for graphical logins:



hello () { echo "hello"; }
export -f hello


It works correctly both when doing bash -l and from a console login.



So, the question is: why, if apparently .profile gets sourced (env vars are successfully exported, and it seems to be explicitly sourced in /etc/gdm3/Xsession) then exporting functions does not work?







bash gdm3






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 10 hours ago









tyriontyrion

1113




1113








  • 1





    What shell sources .profile though? There are a few ordinary shells will read the file when invoked as a login shell. Do you know for a fact that GDM starts a bash login shell, and not a sh login shell?

    – Kusalananda
    9 hours ago













  • No, I do not know for sure. I guess at least some of my assumptions are wrong, otherwise, this should work (unless it is a bug). However, my login shell is bash (specified in /etc/passwd) and the shebang of /etc/gdm3/Xsession is #!/bin/bash. I also confirmed that bash is being used to source .profile by printing $BASH_VERSION to a file.

    – tyrion
    9 hours ago











  • Ok, so bash reads the file. Good. The next thing to note is that an exported function is likely only usable in a bash shell child process. I've just tested exporting a function, starting another (non-bash) shell, and the function is not there. Nor is it there if I start bash from that other shell. It is there if I start a bash shell from the first shell. This means that if you start an interactive bash shell from something that is not bash, the function may not be in the environment.

    – Kusalananda
    9 hours ago






  • 2





    I suspect this may be a manifestation of this question's issue: an intervening dash (or sh, on Ubuntu), or system(), will strip out the exported functions' environment variables.

    – Michael Homer
    9 hours ago











  • @tyrion if you're running gnome, notice that the gnome-session script has a /bin/sh shebang, which means that it will be run with dash, which will wipe off all funny environment variables, as described in Michael Homer's comment. You may change that shebang by hand to #! /bin/bash (not really recommended), but it will be changed back at the next upgrade of the gnome-session-bin package.

    – mosvy
    4 hours ago
















  • 1





    What shell sources .profile though? There are a few ordinary shells will read the file when invoked as a login shell. Do you know for a fact that GDM starts a bash login shell, and not a sh login shell?

    – Kusalananda
    9 hours ago













  • No, I do not know for sure. I guess at least some of my assumptions are wrong, otherwise, this should work (unless it is a bug). However, my login shell is bash (specified in /etc/passwd) and the shebang of /etc/gdm3/Xsession is #!/bin/bash. I also confirmed that bash is being used to source .profile by printing $BASH_VERSION to a file.

    – tyrion
    9 hours ago











  • Ok, so bash reads the file. Good. The next thing to note is that an exported function is likely only usable in a bash shell child process. I've just tested exporting a function, starting another (non-bash) shell, and the function is not there. Nor is it there if I start bash from that other shell. It is there if I start a bash shell from the first shell. This means that if you start an interactive bash shell from something that is not bash, the function may not be in the environment.

    – Kusalananda
    9 hours ago






  • 2





    I suspect this may be a manifestation of this question's issue: an intervening dash (or sh, on Ubuntu), or system(), will strip out the exported functions' environment variables.

    – Michael Homer
    9 hours ago











  • @tyrion if you're running gnome, notice that the gnome-session script has a /bin/sh shebang, which means that it will be run with dash, which will wipe off all funny environment variables, as described in Michael Homer's comment. You may change that shebang by hand to #! /bin/bash (not really recommended), but it will be changed back at the next upgrade of the gnome-session-bin package.

    – mosvy
    4 hours ago










1




1





What shell sources .profile though? There are a few ordinary shells will read the file when invoked as a login shell. Do you know for a fact that GDM starts a bash login shell, and not a sh login shell?

– Kusalananda
9 hours ago







What shell sources .profile though? There are a few ordinary shells will read the file when invoked as a login shell. Do you know for a fact that GDM starts a bash login shell, and not a sh login shell?

– Kusalananda
9 hours ago















No, I do not know for sure. I guess at least some of my assumptions are wrong, otherwise, this should work (unless it is a bug). However, my login shell is bash (specified in /etc/passwd) and the shebang of /etc/gdm3/Xsession is #!/bin/bash. I also confirmed that bash is being used to source .profile by printing $BASH_VERSION to a file.

– tyrion
9 hours ago





No, I do not know for sure. I guess at least some of my assumptions are wrong, otherwise, this should work (unless it is a bug). However, my login shell is bash (specified in /etc/passwd) and the shebang of /etc/gdm3/Xsession is #!/bin/bash. I also confirmed that bash is being used to source .profile by printing $BASH_VERSION to a file.

– tyrion
9 hours ago













Ok, so bash reads the file. Good. The next thing to note is that an exported function is likely only usable in a bash shell child process. I've just tested exporting a function, starting another (non-bash) shell, and the function is not there. Nor is it there if I start bash from that other shell. It is there if I start a bash shell from the first shell. This means that if you start an interactive bash shell from something that is not bash, the function may not be in the environment.

– Kusalananda
9 hours ago





Ok, so bash reads the file. Good. The next thing to note is that an exported function is likely only usable in a bash shell child process. I've just tested exporting a function, starting another (non-bash) shell, and the function is not there. Nor is it there if I start bash from that other shell. It is there if I start a bash shell from the first shell. This means that if you start an interactive bash shell from something that is not bash, the function may not be in the environment.

– Kusalananda
9 hours ago




2




2





I suspect this may be a manifestation of this question's issue: an intervening dash (or sh, on Ubuntu), or system(), will strip out the exported functions' environment variables.

– Michael Homer
9 hours ago





I suspect this may be a manifestation of this question's issue: an intervening dash (or sh, on Ubuntu), or system(), will strip out the exported functions' environment variables.

– Michael Homer
9 hours ago













@tyrion if you're running gnome, notice that the gnome-session script has a /bin/sh shebang, which means that it will be run with dash, which will wipe off all funny environment variables, as described in Michael Homer's comment. You may change that shebang by hand to #! /bin/bash (not really recommended), but it will be changed back at the next upgrade of the gnome-session-bin package.

– mosvy
4 hours ago







@tyrion if you're running gnome, notice that the gnome-session script has a /bin/sh shebang, which means that it will be run with dash, which will wipe off all funny environment variables, as described in Michael Homer's comment. You may change that shebang by hand to #! /bin/bash (not really recommended), but it will be changed back at the next upgrade of the gnome-session-bin package.

– mosvy
4 hours ago












1 Answer
1






active

oldest

votes


















2














This is most likely a specific instance of the issue described in "Why is my BASH_FUNC_foobar%% environment variable unset in shell subprocesses?".



When you export a function in bash, it creates an environment variable with a special name:



$ foo () { echo hello; }
$ export -f foo
$ env

...

BASH_FUNC_foo%%=() { echo hello
}

...


The shell does this because shell functions can't really be exported as functions, so they are converted to "special environment variables" instead. Environment variables can only ever be simple key-value string pairs.



When a bash shell inherits an environment with these sorts of environment variables, it know that they are bash functions, and instantiates the functions with the appropriate names.



According to the POSIX standard:




Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2017 consist solely of uppercase letters, digits, and the <underscore> (_) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.




According to this passage, environment variables containing % in their names are permitted, but other shells, for example the shells that masquerade as /bin/sh on some systems (dash on Ubuntu for example, and ksh on OpenBSD), sanitises the environment and removes any environment variables whose names contain characters other than the explicitly allowed ones.



The /bin/sh shell is used when an application calls system() to start another process.



This all means that if your /bin/sh is dash (which it is on Ubuntu), and if the environment of the final interactive bash shell that you get in a terminal was ever passed (via inheritance from parent process to child process) through a call to system(), or in some other way was inherited by /bin/sh on the way, then your functions would have disappeared1.



The workaround is to define your functions in ~/.bashrc or wherever you define your aliases. Or to get your terminal to spawn a bash login shell.



1Unfortunately, I don't run either of GDM or Ubuntu, so I can't currently run strace on the processes involved in the login procedure to see what actually happens there.





Example showing a function disappearing between one bash shell and another, when the other bash shell is invoked by dash:



$ foo () { echo hello; }
$ export -f foo

$ dash -c 'bash -c foo'
bash: foo: command not found


Example of using yash instead, which does not remove the function:



$ yash -c 'bash -c foo'
hello


Likewise, ksh on OpenBSD sanitises, while ksh93 and zsh do not:



$ ksh -c 'bash -c foo'
bash: foo: command not found
$ ksh93 -c 'bash -c foo'
hello
$ zsh -c 'bash -c foo'
hello


Note that in all cases where the output is hello above, the intermediate shell is totally unaware that the specially named environment variable constitutes a function:



$ yash -c 'foo'
yash: no such command `foo'
$ ksh93 -c 'foo'
ksh93: foo: not found
$ zsh -c 'foo'
zsh:1: command not found: foo





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',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    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%2f505358%2fhow-to-export-functions-from-profile-during-graphical-login%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    This is most likely a specific instance of the issue described in "Why is my BASH_FUNC_foobar%% environment variable unset in shell subprocesses?".



    When you export a function in bash, it creates an environment variable with a special name:



    $ foo () { echo hello; }
    $ export -f foo
    $ env

    ...

    BASH_FUNC_foo%%=() { echo hello
    }

    ...


    The shell does this because shell functions can't really be exported as functions, so they are converted to "special environment variables" instead. Environment variables can only ever be simple key-value string pairs.



    When a bash shell inherits an environment with these sorts of environment variables, it know that they are bash functions, and instantiates the functions with the appropriate names.



    According to the POSIX standard:




    Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2017 consist solely of uppercase letters, digits, and the <underscore> (_) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.




    According to this passage, environment variables containing % in their names are permitted, but other shells, for example the shells that masquerade as /bin/sh on some systems (dash on Ubuntu for example, and ksh on OpenBSD), sanitises the environment and removes any environment variables whose names contain characters other than the explicitly allowed ones.



    The /bin/sh shell is used when an application calls system() to start another process.



    This all means that if your /bin/sh is dash (which it is on Ubuntu), and if the environment of the final interactive bash shell that you get in a terminal was ever passed (via inheritance from parent process to child process) through a call to system(), or in some other way was inherited by /bin/sh on the way, then your functions would have disappeared1.



    The workaround is to define your functions in ~/.bashrc or wherever you define your aliases. Or to get your terminal to spawn a bash login shell.



    1Unfortunately, I don't run either of GDM or Ubuntu, so I can't currently run strace on the processes involved in the login procedure to see what actually happens there.





    Example showing a function disappearing between one bash shell and another, when the other bash shell is invoked by dash:



    $ foo () { echo hello; }
    $ export -f foo

    $ dash -c 'bash -c foo'
    bash: foo: command not found


    Example of using yash instead, which does not remove the function:



    $ yash -c 'bash -c foo'
    hello


    Likewise, ksh on OpenBSD sanitises, while ksh93 and zsh do not:



    $ ksh -c 'bash -c foo'
    bash: foo: command not found
    $ ksh93 -c 'bash -c foo'
    hello
    $ zsh -c 'bash -c foo'
    hello


    Note that in all cases where the output is hello above, the intermediate shell is totally unaware that the specially named environment variable constitutes a function:



    $ yash -c 'foo'
    yash: no such command `foo'
    $ ksh93 -c 'foo'
    ksh93: foo: not found
    $ zsh -c 'foo'
    zsh:1: command not found: foo





    share|improve this answer






























      2














      This is most likely a specific instance of the issue described in "Why is my BASH_FUNC_foobar%% environment variable unset in shell subprocesses?".



      When you export a function in bash, it creates an environment variable with a special name:



      $ foo () { echo hello; }
      $ export -f foo
      $ env

      ...

      BASH_FUNC_foo%%=() { echo hello
      }

      ...


      The shell does this because shell functions can't really be exported as functions, so they are converted to "special environment variables" instead. Environment variables can only ever be simple key-value string pairs.



      When a bash shell inherits an environment with these sorts of environment variables, it know that they are bash functions, and instantiates the functions with the appropriate names.



      According to the POSIX standard:




      Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2017 consist solely of uppercase letters, digits, and the <underscore> (_) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.




      According to this passage, environment variables containing % in their names are permitted, but other shells, for example the shells that masquerade as /bin/sh on some systems (dash on Ubuntu for example, and ksh on OpenBSD), sanitises the environment and removes any environment variables whose names contain characters other than the explicitly allowed ones.



      The /bin/sh shell is used when an application calls system() to start another process.



      This all means that if your /bin/sh is dash (which it is on Ubuntu), and if the environment of the final interactive bash shell that you get in a terminal was ever passed (via inheritance from parent process to child process) through a call to system(), or in some other way was inherited by /bin/sh on the way, then your functions would have disappeared1.



      The workaround is to define your functions in ~/.bashrc or wherever you define your aliases. Or to get your terminal to spawn a bash login shell.



      1Unfortunately, I don't run either of GDM or Ubuntu, so I can't currently run strace on the processes involved in the login procedure to see what actually happens there.





      Example showing a function disappearing between one bash shell and another, when the other bash shell is invoked by dash:



      $ foo () { echo hello; }
      $ export -f foo

      $ dash -c 'bash -c foo'
      bash: foo: command not found


      Example of using yash instead, which does not remove the function:



      $ yash -c 'bash -c foo'
      hello


      Likewise, ksh on OpenBSD sanitises, while ksh93 and zsh do not:



      $ ksh -c 'bash -c foo'
      bash: foo: command not found
      $ ksh93 -c 'bash -c foo'
      hello
      $ zsh -c 'bash -c foo'
      hello


      Note that in all cases where the output is hello above, the intermediate shell is totally unaware that the specially named environment variable constitutes a function:



      $ yash -c 'foo'
      yash: no such command `foo'
      $ ksh93 -c 'foo'
      ksh93: foo: not found
      $ zsh -c 'foo'
      zsh:1: command not found: foo





      share|improve this answer




























        2












        2








        2







        This is most likely a specific instance of the issue described in "Why is my BASH_FUNC_foobar%% environment variable unset in shell subprocesses?".



        When you export a function in bash, it creates an environment variable with a special name:



        $ foo () { echo hello; }
        $ export -f foo
        $ env

        ...

        BASH_FUNC_foo%%=() { echo hello
        }

        ...


        The shell does this because shell functions can't really be exported as functions, so they are converted to "special environment variables" instead. Environment variables can only ever be simple key-value string pairs.



        When a bash shell inherits an environment with these sorts of environment variables, it know that they are bash functions, and instantiates the functions with the appropriate names.



        According to the POSIX standard:




        Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2017 consist solely of uppercase letters, digits, and the <underscore> (_) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.




        According to this passage, environment variables containing % in their names are permitted, but other shells, for example the shells that masquerade as /bin/sh on some systems (dash on Ubuntu for example, and ksh on OpenBSD), sanitises the environment and removes any environment variables whose names contain characters other than the explicitly allowed ones.



        The /bin/sh shell is used when an application calls system() to start another process.



        This all means that if your /bin/sh is dash (which it is on Ubuntu), and if the environment of the final interactive bash shell that you get in a terminal was ever passed (via inheritance from parent process to child process) through a call to system(), or in some other way was inherited by /bin/sh on the way, then your functions would have disappeared1.



        The workaround is to define your functions in ~/.bashrc or wherever you define your aliases. Or to get your terminal to spawn a bash login shell.



        1Unfortunately, I don't run either of GDM or Ubuntu, so I can't currently run strace on the processes involved in the login procedure to see what actually happens there.





        Example showing a function disappearing between one bash shell and another, when the other bash shell is invoked by dash:



        $ foo () { echo hello; }
        $ export -f foo

        $ dash -c 'bash -c foo'
        bash: foo: command not found


        Example of using yash instead, which does not remove the function:



        $ yash -c 'bash -c foo'
        hello


        Likewise, ksh on OpenBSD sanitises, while ksh93 and zsh do not:



        $ ksh -c 'bash -c foo'
        bash: foo: command not found
        $ ksh93 -c 'bash -c foo'
        hello
        $ zsh -c 'bash -c foo'
        hello


        Note that in all cases where the output is hello above, the intermediate shell is totally unaware that the specially named environment variable constitutes a function:



        $ yash -c 'foo'
        yash: no such command `foo'
        $ ksh93 -c 'foo'
        ksh93: foo: not found
        $ zsh -c 'foo'
        zsh:1: command not found: foo





        share|improve this answer















        This is most likely a specific instance of the issue described in "Why is my BASH_FUNC_foobar%% environment variable unset in shell subprocesses?".



        When you export a function in bash, it creates an environment variable with a special name:



        $ foo () { echo hello; }
        $ export -f foo
        $ env

        ...

        BASH_FUNC_foo%%=() { echo hello
        }

        ...


        The shell does this because shell functions can't really be exported as functions, so they are converted to "special environment variables" instead. Environment variables can only ever be simple key-value string pairs.



        When a bash shell inherits an environment with these sorts of environment variables, it know that they are bash functions, and instantiates the functions with the appropriate names.



        According to the POSIX standard:




        Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2017 consist solely of uppercase letters, digits, and the <underscore> (_) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names. Uppercase and lowercase letters shall retain their unique identities and shall not be folded together. The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.




        According to this passage, environment variables containing % in their names are permitted, but other shells, for example the shells that masquerade as /bin/sh on some systems (dash on Ubuntu for example, and ksh on OpenBSD), sanitises the environment and removes any environment variables whose names contain characters other than the explicitly allowed ones.



        The /bin/sh shell is used when an application calls system() to start another process.



        This all means that if your /bin/sh is dash (which it is on Ubuntu), and if the environment of the final interactive bash shell that you get in a terminal was ever passed (via inheritance from parent process to child process) through a call to system(), or in some other way was inherited by /bin/sh on the way, then your functions would have disappeared1.



        The workaround is to define your functions in ~/.bashrc or wherever you define your aliases. Or to get your terminal to spawn a bash login shell.



        1Unfortunately, I don't run either of GDM or Ubuntu, so I can't currently run strace on the processes involved in the login procedure to see what actually happens there.





        Example showing a function disappearing between one bash shell and another, when the other bash shell is invoked by dash:



        $ foo () { echo hello; }
        $ export -f foo

        $ dash -c 'bash -c foo'
        bash: foo: command not found


        Example of using yash instead, which does not remove the function:



        $ yash -c 'bash -c foo'
        hello


        Likewise, ksh on OpenBSD sanitises, while ksh93 and zsh do not:



        $ ksh -c 'bash -c foo'
        bash: foo: command not found
        $ ksh93 -c 'bash -c foo'
        hello
        $ zsh -c 'bash -c foo'
        hello


        Note that in all cases where the output is hello above, the intermediate shell is totally unaware that the specially named environment variable constitutes a function:



        $ yash -c 'foo'
        yash: no such command `foo'
        $ ksh93 -c 'foo'
        ksh93: foo: not found
        $ zsh -c 'foo'
        zsh:1: command not found: foo






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 6 hours ago

























        answered 6 hours ago









        KusalanandaKusalananda

        134k17255418




        134k17255418






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Unix & Linux Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f505358%2fhow-to-export-functions-from-profile-during-graphical-login%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Loup dans la culture

            How to solve the problem of ntp “Unable to contact time server” from KDE?

            Connection limited (no internet access)