linuxbashshellgosh

Replicating /etc/profile.d under ~/.profile.d by copying the code from /etc/profile and changing the path


I'm trying to replicate the functionality of /etc/profile.d by copying the segment of /etc/profile that runs the scripts in profile.d in my ~/.profile, and have it run scripts under ~/.profile.d.

Here's my ~/.profile.

# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
    PATH="$HOME/.local/bin:$PATH"
fi

## Begin user section:
## Add $HOME/.profile.d
if [ -d "$HOME/.profile.d" ]; then
  for i in '$HOME/.profile.d/*.sh'; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi

Here's the golang.sh mentioned in that error:

GOPATH=$(go env GOPATH)
export PATH=$GOPATH/bin:$PATH
unset GOPATH

I also copied lines 33-35 from my ~/.profile into a separate script called test.sh and ran that as i="$HOME/.profile.d/golang.sh to confirm those lines do what I expect:

if [ -r $i ]; then
      echo "Can read ${i}" # Prior line is checking if the script file can be read, so if it does echo it here.
      . $i # this is what it originally did, sourcing the scripts inside a for loop.

fi

And, it does. I'm really confused. My understanding is the section I copied from /etc/profile iterates over every file in the given path (/etc/profile.d in the original, $HOME/.profile.d in my version), and checks if it can read them, then sources them (which is distinct from running them normally) if it can.

I have since run this script through ShellCheck as recommended by the bash tag, and it said to use single quotes in the for statement since double quotes break those. That fixed the error when logging into Cinnamon, but it still doesn't source the scripts in ~/.profile.d like I was expecting it to.

As you may have gathered, I'm a shell scripting noob.

I should note golang.sh has not been made executable. I don't think it needs to be, since it's being sourced and not executed, and /etc/profile.d scripts don't have +x set either. Also, doing . $HOME/.profile.d/golang.sh or source $HOME/.profile.d/golang.sh still sets my path like I expect.


Solution

  • Your for loop

    for i in '$HOME/.profile.d/*.sh'; do
    > echo "$i"
    > done
    

    produces

    $HOME/.profile.d/*.sh
    

    because you have single quotes, so it's not expanded. Remove the single quotes. As mentioned by Toby Speight, you can double quote $HOME (e.g. "$HOME"/.profile.d/*.sh) to expand that part but not the rest of the expression.