Search code examples
bashpathgit-post-receive

PATH in post-receive hook doesn't contain PATH as set in bashrc


How can I set the PATH on Ubuntu in a way where its variables that I set are also set in a post-receive script? Currently I'm doing it via the ~/.bashrc file like this:

export PATH="$PATH:/opt/mssql-tools/bin"

but can't see any change in the PATH if I print it from the hook. Therefore, if I try to execute the command in question in the hook, I get

remote: FileNotFoundError: [Errno 2] No such file or directory: 'sqlcmd': 'sqlcmd'

So the only solution I see right now is defining it again in the post-receive hook itself, like this:

export PATH="$PATH:/opt/mssql-tools/bin"

Is there a better way?

Thank you!


Solution

  • First, a small bit of file setup:

    $ mkdir /tmp/dir1 /tmp/dir2
    $ date > /tmp/dir1/foo
    $ date > /tmp/dir2/bar
    

    Now, consider a simple script:

    $ chmod 755 foo.sh; cat foo.sh
    #!/bin/sh
    
    # intentionally set an inadequate PATH:
    
    export PATH=""    
    
    # script to 'ls' two dirs, show that output, and show the diff of the two.
    
    ls /tmp/dir1 > temp1
    ls /tmp/dir2 > temp2
    
    echo /tmp/dir1:
    cat temp1
    
    echo /tmp/dir2:
    cat temp2
    
    diff temp1 temp2
    

    The script is well-formed syntactically, but let's see what happens:

    $ ./foo.sh
    ./foo.sh: ls: not found
    ./foo.sh: ls: not found
    /tmp/dir1:
    ./foo.sh: cat: not found
    /tmp/dir2:
    ./foo.sh: cat: not found
    ./foo.sh: diff: not found
    

    The path isn't sufficient for the script interpreter to find the executables the script wants to run. Three separate executables fail to load: ls, cat, and diff. So let's help it a little. Since ls typically resides in the /bin directory, let's edit PATH to become:

    export PATH="/bin"
    

    and try again:

    $ ./foo.sh
    /tmp/dir1:
    foo
    /tmp/dir2:
    bar
    ./foo.sh: diff: not found
    

    Well, ls runs okay now. That's progress. And since cat also lives in /bin, adding /bin to the path killed two birds with one stone. But diff still isn't being found, because diff lives in /usr/bin. So let's add that to the PATH:

    export PATH="/bin:/usr/bin"
    

    and try again:

    $ ./foo.sh 
    /tmp/dir1:
    foo
    /tmp/dir2:
    bar
    1c1
    < foo
    ---
    > bar
    

    Voila! No more errors, because the PATH variable contains everything needed to allow the script interpreter to locate the executables that are called by the script.

    The other way is to tell PATH to butt out and specify your own path to executables. This method is sometimes handy when you might not trust or desire the "standard" executables, for whatever reason. When structuring a script in this fashion, I prefer to use variables for the executables I want to reference, so that if^H^Hwhen the location changes, I can just change the variables and don't have to search the entire script for all the invocations of that executable.

    $ chmod 755 bar.sh; cat bar.sh
    #!/bin/sh
    
    # intentionally set an inadequate PATH:
    
    export PATH=""
    
    # ls lives in /bin:
    LS="/bin/ls"
    
    # so does cat:
    CAT="/bin/cat"
    
    # but diff lives in /usr/bin:
    DIFF="/usr/bin/diff"
    
    # script to 'ls' two dirs, show that output, and show the diff of the two.
    
    $LS /tmp/dir1 > temp1
    $LS /tmp/dir2 > temp2
    
    echo /tmp/dir1:
    $CAT temp1
    
    echo /tmp/dir2:
    $CAT temp2
    
    $DIFF temp1 temp2
    

    And the output:

    $ ./bar.sh
    /tmp/dir1:
    foo
    /tmp/dir2:
    bar
    1c1
    < foo
    ---
    > bar
    

    You can mix and match these approaches, by specifying a PATH that includes most things, and specifying absolute paths for the others, but your problem is arising because you have not done that.

    You either need to specify a full and adequate PATH in your hook script, and/or specify absolute paths to the remaining executables (if any) that reside outside whatever PATH variable your hook script currently uses.