Getting GNU Make to parse shell config files in OSX? - macos

I've got a makefile for installing my personal repo of config files, part of which is compiling my emacs scripts:
compile:
emacs -batch --eval "(progn (load \"~/.emacs\") (byte-recompile-directory \"~/.emacs.d\" 0))"
The problem is, on OSX, I have an alias called "emacs" that points to the Emacs.app binary for use in a terminal, this is defined in my ~/.bash_profile.
Now, no matter what I do, I can't seem to get the shell that Make is calling to read a startup file to load that alias, so that compilation step always fails.
Does anyone know how to do this?

.bash_profile is only read by interactive login shells. Exported environment variables set in it are inherited through the process environment, which means that these settings are generally available to all programs the user starts (if bash is indeed the login shell, of course).
No such inheritance happens for aliases, though. Bash supports exported functions, but that's an obscure feature which can easily break other programs (for example, those which assume that environment variable values do not contain newlines). If you go that route, you may have to use .bashrc instead, to make sure that these functions are exported by interactive bash shells which are not login shells.
I expected the easiest solution is to put a directory like $HOME/bin on the PATH (in .bash_profile or .bashrc, whatever works best) and put an emacs wrapper script into that directory which invokes the actual binary using exec /path/to/Emacs.app "$#" (or maybe just a symbolic link would do).

That is very strange. Aliases are not exported to sub-shells, and the .bash_profile script is only run by interactive shells: make doesn't invoke an interactive shell (by default). So, it's hard to understand how the shell make invokes would see that alias based on the information you've provided.
Maybe you set the BASH_ENV shell variable somewhere? You should never do that, unless you really know what you're doing.
Maybe you reset make's .SHELLFLAGS variable to force a login shell? You shouldn't to that either.
Anyway, you can try using command which avoids aliases etc. Unfortunately make doesn't know this is a shell-built in, so you have to convince it to run a shell. This will be fixed in the next release of GNU make but Apple will never ship that.
compile:
command emacs -batch --eval "(progn (load \"~/.emacs\") (byte-recompile-directory \"~/.emacs.d\" 0))" && true

Related

How to determine which .bash_profile .profile .bashrc .zshrc to use? [duplicate]

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I've used a number of different *nix-based systems of the years, and it seems like every flavor of Bash I use has a different algorithm for deciding which startup scripts to run. For the purposes of tasks like setting up environment variables and aliases and printing startup messages (e.g. MOTDs), which startup script is the appropriate place to do these?
What's the difference between putting things in .bashrc, .bash_profile, and .environment? I've also seen other files such as .login, .bash_login, and .profile; are these ever relevant? What are the differences in which ones get run when logging in physically, logging in remotely via ssh, and opening a new terminal window? Are there any significant differences across platforms (including Mac OS X (and its Terminal.app) and Cygwin Bash)?
The main difference with shell config files is that some are only read by "login" shells (eg. when you login from another host, or login at the text console of a local unix machine). these are the ones called, say, .login or .profile or .zlogin (depending on which shell you're using).
Then you have config files that are read by "interactive" shells (as in, ones connected to a terminal (or pseudo-terminal in the case of, say, a terminal emulator running under a windowing system). these are the ones with names like .bashrc, .tcshrc, .zshrc, etc.
bash complicates this in that .bashrc is only read by a shell that's both interactive and non-login, so you'll find most people end up telling their .bash_profile to also read .bashrc with something like
[[ -r ~/.bashrc ]] && . ~/.bashrc
Other shells behave differently - eg with zsh, .zshrc is always read for an interactive shell, whether it's a login one or not.
The manual page for bash explains the circumstances under which each file is read. Yes, behaviour is generally consistent between machines.
.profile is simply the login script filename originally used by /bin/sh. bash, being generally backwards-compatible with /bin/sh, will read .profile if one exists.
That's simple. It's explained in man bash:
/bin/bash
The bash executable
/etc/profile
The systemwide initialization file, executed for login shells
~/.bash_profile
The personal initialization file, executed for login shells
~/.bashrc
The individual per-interactive-shell startup file
~/.bash_logout
The individual login shell cleanup file, executed when a login shell exits
~/.inputrc
Individual readline initialization file
Login shells are the ones that are read one you login (so, they are not executed when merely starting up xterm, for example). There are other ways to login. For example using an X display manager. Those have other ways to read and export environment variables at login time.
Also read the INVOCATION chapter in the manual. It says "The following paragraphs describe how bash executes its startup files.", i think that's a spot-on :) It explains what an "interactive" shell is too.
Bash does not know about .environment. I suspect that's a file of your distribution, to set environment variables independent of the shell that you drive.
Classically, ~/.profile is used by Bourne Shell, and is probably supported by Bash as a legacy measure. Again, ~/.login and ~/.cshrc were used by C Shell - I'm not sure that Bash uses them at all.
The ~/.bash_profile would be used once, at login. The ~/.bashrc script is read every time a shell is started. This is analogous to /.cshrc for C Shell.
One consequence is that stuff in ~/.bashrc should be as lightweight (minimal) as possible to reduce the overhead when starting a non-login shell.
I believe the ~/.environment file is a compatibility file for Korn Shell.
I found information about .bashrc and .bash_profile here to sum it up:
.bash_profile is executed when you
login. Stuff you put in there might be
your PATH and other important
environment variables.
.bashrc is used for non login shells.
I'm not sure what that means. I know
that RedHat
executes it everytime you start
another shell (su to this user or
simply calling bash again) You might
want to put aliases in there but again
I am not sure what that means. I
simply ignore it myself.
.profile is the equivalent of
.bash_profile for the root. I think
the name is changed to let other
shells (csh, sh, tcsh) use it as well.
(you don't need one as a user)
There is also .bash_logout wich
executes at, yeah good guess...logout.
You might want to stop deamons or even
make a little housekeeping . You can
also add "clear" there if you want to
clear the screen when you log out.
Also there is a complete follow up on each of the configurations files here
These are probably even distro.-dependant, not all distros choose to have each configuraton with them and some have even more. But when they have the same name, they usualy include the same content.
According to Josh Staiger, Mac OS X's Terminal.app actually runs a login shell rather than a non-login shell by default for each new terminal window, calling .bash_profile instead of .bashrc.
He recommends:
Most of the time you don’t want to maintain two separate config files
for login and non-login shells — when you set a PATH, you want it to
apply to both. You can fix this by sourcing .bashrc from your
.bash_profile file, then putting PATH and common settings in .bashrc.
To do this, add the following lines to .bash_profile:
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
Now when you login to your
machine from a console .bashrc will be called.
A good place to look at is the man page of bash. Here's an online version. Look for "INVOCATION" section.
I have used Debian-family distros which appear to execute .profile, but not .bash_profile,
whereas RHEL derivatives execute .bash_profile before .profile.
It seems to be a mess when you have to set up environment variables to work in any Linux OS.

Is there a standard place that the PAGER environment variable is set by default for all users in Ubuntu Linux? [duplicate]

Can I have certain settings that are universal for all my users?
As well as /etc/profile which others have mentioned, some Linux systems now use a directory /etc/profile.d/; any .sh files in there will be sourced by /etc/profile. It's slightly neater to keep your custom environment stuff in these files than to just edit /etc/profile.
If your LinuxOS has this file:
/etc/environment
You can use it to permanently set environmental variables for all users.
Extracted from: http://www.sysadmit.com/2016/04/linux-variables-de-entorno-permanentes.html
man 8 pam_env
man 5 pam_env.conf
If all login services use PAM, and all login services have session required pam_env.so in their respective /etc/pam.d/* configuration files, then all login sessions will have some environment variables set as specified in pam_env's configuration file.
On most modern Linux distributions, this is all there by default -- just add your desired global environment variables to /etc/security/pam_env.conf.
This works regardless of the user's shell, and works for graphical logins too (if xdm/kdm/gdm/entrance/… is set up like this).
Amazingly, Unix and Linux do not actually have a place to set global environment variables. The best you can do is arrange for any specific shell to have a site-specific initialization.
If you put it in /etc/profile, that will take care of things for most posix-compatible shell users. This is probably "good enough" for non-critical purposes.
But anyone with a csh or tcsh shell won't see it, and I don't believe csh has a global initialization file.
Some interesting excerpts from the bash manpage:
When bash is invoked as an interactive
login shell, or as a non-interactive
shell with the --login option, it
first reads and executes commands from
the file /etc/profile, if that file
exists. After reading that file, it
looks for ~/.bash_profile,
~/.bash_login, and ~/.profile, in that
order, and reads and executes commands
from the first one that exists and is
readable. The --noprofile option may
be used when the shell is started to
inhibit this behavior.
...
When an
interactive shell that is not a login
shell is started, bash reads and
executes commands from
/etc/bash.bashrc and ~/.bashrc, if
these files exist. This may be
inhibited by using the --norc option.
The --rcfile file option will force
bash to read and execute commands from
file instead of /etc/bash.bashrc and
~/.bashrc.
So have a look at /etc/profile or /etc/bash.bashrc, these files are the right places for global settings. Put something like this in them to set up an environement variable:
export MY_VAR=xxx
Every process running under the Linux kernel receives its own, unique environment that it inherits from its parent. In this case, the parent will be either a shell itself (spawning a sub shell), or the 'login' program (on a typical system).
As each process' environment is protected, there is no way to 'inject' an environmental variable to every running process, so even if you modify the default shell .rc / profile, it won't go into effect until each process exits and reloads its start up settings.
Look in /etc/ to modify the default start up variables for any particular shell. Just realize that users can (and often do) change them in their individual settings.
Unix is designed to obey the user, within limits.
NB: Bash is not the only shell on your system. Pay careful attention to what the /bin/sh symbolic link actually points to. On many systems, this could actually be dash which is (by default, with no special invocation) POSIXLY correct. Therefore, you should take care to modify both defaults, or scripts that start with /bin/sh will not inherit your global defaults. Similarly, take care to avoid syntax that only bash understands when editing both, aka avoiding bashisms.
Using PAM is execellent.
# modify the display PAM
$ cat /etc/security/pam_env.conf
# BEFORE: $ export DISPLAY=:0.0 && python /var/tmp/myproject/click.py &
# AFTER : $ python $abc/click.py &
DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY}
abc DEFAULT=/var/tmp/myproject

How to implicitly run a shell script sourced?

I have made a shell script to run as terminal command, but the cd commands inside it is not effective and hence I want to run it with source so that the cd commands take effect.
script name : "project.sh"
I added this file to /usr/local/bin, made it executable by chmod +x project.sh and it runs fine, but the cd command is not working.
I know it runs in a child process and hence at the end terminal returns back to the starting directory, rendering no effect of cd commands inside project.sh.
The solutions presented at Sol:1 do not work for me, because they asks me to run source <file>, which is not possible if I want to use it as Bash command.
You use the source command:
source /usr/local/bin/project.sh
There's no way to make this happen automatically by typing the script name, that always runs the script in a subprocess. If you don't want to have to type this all out, you could create an alias in your .bashrc to simplify it:
alias project='source /usr/local/bin/project.sh'
Then typing project will be translated to that full command.
Of course, source <file> is a Bash command - it uses the source builtin to run script <file> in the context of the current shell rather than in a child process, thus allowing commands in <file> to change the current shell's environment, such as in terms of the working directory (using cd).
Using source, or its alias ., is (ultimately) the only way to achieve that.
If your intent is not to have to invoke <script> explicitly with source, you have two options, both of which are best defined in your Bash profile, ~/.bash_profile (since you're on OS X; on Linux, use ~/.bashrc[1]):
I'll assume that your script is /path/to/foo, and that you want to invoke it sourced as just foo:
Option 1: Define an alias: alias foo='source "/path/to/foo"'
Option 2: Define a function: foo() { source "/path/to/foo"; }
Both aliases and functions execute in the current shell, allowing you to effectively hide the source call behind a single command; aliases are generally a little easier to define, but functions offer more flexibility.
By virtue of the alias / function being defined in your Bash profile, which itself is implicitly sourced, the commands in /path/to/foo will affect your interactive shells' environment.
Note: Either definition of foo will only be available in interactive shells (those that (automatically) source ~/.bash_profile).
Additional steps would be needed to make foo work inside non-sourced scripts as well, but at that point you should ask yourself whether you're obscuring things by not making the fact that /path/to/foo is getting sourced explicit.
If you're writing a script that must be sourced for distribution to others:
Install the sourcing command in the user's shell profile / initialization file (as described above) on installation of your script.
If there is no installation process (and also to enable on-demand installation in general), implement a command-line option for your script such as i (--install) that performs this installation on demand.
Preferably, also implement an uninstallation option.
Either way, build logic into the script so that it refuses to run when run without sourcing, and have the error message contain instructions on how to install sourcing.
See this answer for how to detect sourcing.
A real-world implementation of the above - although more elaborate due to being multi-shell - is my typex utility; source code here.
[1] On OS X, Bash instances started by Terminal.app are login shells, which means that the only (user-specific) file that is automatically sourced on startup is ~/.bash_profile.
By contrast, on most Linux systems Bash instances are non-login shells, where only ~/.bashrc is automatically sourced.
While it is common practice to source ~/.bashrc from one's ~/.bash_profile, this has to be configured manually and therefore cannot be relied upon blindly.

Emacs shell-specific environment variables

In native emacs on windows, how can I specify environment variables for launching my shell inside emacs without modifying emacs' environment? In my specific case I'd like to set HOME to a cygwin-specific value for zsh without modifying where emacs thinks it's config file lives.
I've tried some things like changing my shell to env -u HOME ...\zsh.exe, but that seems to break (shell-command) (it appeared to involve argument order).
If this command existed, it would probably do what I want:
(setq explicit-zsh-environment '("HOME" nil))
I've read a bunch of related questions like (How can I run Cygwin Bash Shell from within Emacs?), but the unusual part for me is that all my config files are cygwin-ln-ed or windows-mklink-ed into a git repo and cygwin and windows take very different and incompatible approaches to symlinks.
Is this about running zsh as a shell inside Emacs (i.e. not about starting Emacs from a zsh shell), and having the environment that the inferior zsh process sees be different to the environment that Emacs has?
If so, you can bind the C-hv process-environment variable when you start a process. e.g.:
(let ((process-environment '("HOME=/tmp")))
(call-interactively 'shell))
$ echo $HOME
/tmp
From the Emacs manual:
Emacs sends the new shell the contents of the file ~/.emacs_shellname as input, if it exists, where shellname is the name of the file that the shell was loaded from. For example, if you use bash, the file sent to it is ~/.emacs_bash. If this file is not found, Emacs tries with ~/.emacs.d/init_shellname.sh.
So for zsh you would put inside ~/.emacs.d/init_zsh.sh something like:
export HOME=/tmp

What's the difference between .bashrc, .bash_profile, and .environment?

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I've used a number of different *nix-based systems of the years, and it seems like every flavor of Bash I use has a different algorithm for deciding which startup scripts to run. For the purposes of tasks like setting up environment variables and aliases and printing startup messages (e.g. MOTDs), which startup script is the appropriate place to do these?
What's the difference between putting things in .bashrc, .bash_profile, and .environment? I've also seen other files such as .login, .bash_login, and .profile; are these ever relevant? What are the differences in which ones get run when logging in physically, logging in remotely via ssh, and opening a new terminal window? Are there any significant differences across platforms (including Mac OS X (and its Terminal.app) and Cygwin Bash)?
The main difference with shell config files is that some are only read by "login" shells (eg. when you login from another host, or login at the text console of a local unix machine). these are the ones called, say, .login or .profile or .zlogin (depending on which shell you're using).
Then you have config files that are read by "interactive" shells (as in, ones connected to a terminal (or pseudo-terminal in the case of, say, a terminal emulator running under a windowing system). these are the ones with names like .bashrc, .tcshrc, .zshrc, etc.
bash complicates this in that .bashrc is only read by a shell that's both interactive and non-login, so you'll find most people end up telling their .bash_profile to also read .bashrc with something like
[[ -r ~/.bashrc ]] && . ~/.bashrc
Other shells behave differently - eg with zsh, .zshrc is always read for an interactive shell, whether it's a login one or not.
The manual page for bash explains the circumstances under which each file is read. Yes, behaviour is generally consistent between machines.
.profile is simply the login script filename originally used by /bin/sh. bash, being generally backwards-compatible with /bin/sh, will read .profile if one exists.
That's simple. It's explained in man bash:
/bin/bash
The bash executable
/etc/profile
The systemwide initialization file, executed for login shells
~/.bash_profile
The personal initialization file, executed for login shells
~/.bashrc
The individual per-interactive-shell startup file
~/.bash_logout
The individual login shell cleanup file, executed when a login shell exits
~/.inputrc
Individual readline initialization file
Login shells are the ones that are read one you login (so, they are not executed when merely starting up xterm, for example). There are other ways to login. For example using an X display manager. Those have other ways to read and export environment variables at login time.
Also read the INVOCATION chapter in the manual. It says "The following paragraphs describe how bash executes its startup files.", i think that's a spot-on :) It explains what an "interactive" shell is too.
Bash does not know about .environment. I suspect that's a file of your distribution, to set environment variables independent of the shell that you drive.
Classically, ~/.profile is used by Bourne Shell, and is probably supported by Bash as a legacy measure. Again, ~/.login and ~/.cshrc were used by C Shell - I'm not sure that Bash uses them at all.
The ~/.bash_profile would be used once, at login. The ~/.bashrc script is read every time a shell is started. This is analogous to /.cshrc for C Shell.
One consequence is that stuff in ~/.bashrc should be as lightweight (minimal) as possible to reduce the overhead when starting a non-login shell.
I believe the ~/.environment file is a compatibility file for Korn Shell.
I found information about .bashrc and .bash_profile here to sum it up:
.bash_profile is executed when you
login. Stuff you put in there might be
your PATH and other important
environment variables.
.bashrc is used for non login shells.
I'm not sure what that means. I know
that RedHat
executes it everytime you start
another shell (su to this user or
simply calling bash again) You might
want to put aliases in there but again
I am not sure what that means. I
simply ignore it myself.
.profile is the equivalent of
.bash_profile for the root. I think
the name is changed to let other
shells (csh, sh, tcsh) use it as well.
(you don't need one as a user)
There is also .bash_logout wich
executes at, yeah good guess...logout.
You might want to stop deamons or even
make a little housekeeping . You can
also add "clear" there if you want to
clear the screen when you log out.
Also there is a complete follow up on each of the configurations files here
These are probably even distro.-dependant, not all distros choose to have each configuraton with them and some have even more. But when they have the same name, they usualy include the same content.
According to Josh Staiger, Mac OS X's Terminal.app actually runs a login shell rather than a non-login shell by default for each new terminal window, calling .bash_profile instead of .bashrc.
He recommends:
Most of the time you don’t want to maintain two separate config files
for login and non-login shells — when you set a PATH, you want it to
apply to both. You can fix this by sourcing .bashrc from your
.bash_profile file, then putting PATH and common settings in .bashrc.
To do this, add the following lines to .bash_profile:
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
Now when you login to your
machine from a console .bashrc will be called.
A good place to look at is the man page of bash. Here's an online version. Look for "INVOCATION" section.
I have used Debian-family distros which appear to execute .profile, but not .bash_profile,
whereas RHEL derivatives execute .bash_profile before .profile.
It seems to be a mess when you have to set up environment variables to work in any Linux OS.

Resources