Lets say I have this bash script (test):
#!/usr/bin/env bash
source ~/.zshrc
In my .zshrc, I have the following:
autoload -U compinit
compinit
When I try and run 'bash test' from my terminal window (zsh), I get errors saying autoload and compinit commands are not found. If I just do source ~/.zshrc from the command line, it works fine.
I am trying to setup my development environment, similar to this blog, but when the scripts try and source the .zshrc file it fails.
Any insight would be appreciated.
In your script, you're using bash to run a zsh script. You might as well ask the python interpreter to parse perl.
Either change bash to zsh in the shebang line or write the script with bash commands.
It's not quite as bad as python vs. perl. Both bash and zsh are derived from the Bourne shell (whose behavior is standardized by POSIX), so any script designed to work with /bin/sh is likely to work with either bash or zsh.
Normally your ~/.zshrc, as the name implies, is designed to be used with zsh, and will typically include zsh-specific commands like autoload and compinit.
You can make those commands conditional, for example:
if [ "$ZSH_VERSION" ] ; then
autoload -U compinit
compinit
fi
But of course that means you won't get the functionality of those commands, unless you can figure out a way to emulate them in bash. (I'm not familiar with either command, so I can't help you there.)
(Note that this will fail if you've done set -u or set -o nounset in your bash shell.)
But if you're going to be using both zsh and bash, it probably makes a lot more sense to have separate ~/.bashrc and ~/.zshrc files, and use each one only with the shell for which it's designed. If you want to avoid duplication, each one can source a third file containing common commands.
(And based on the comments, it's likely you're doing the wrong thing in the first place.)
Related
I use vim's :! external command function all the time, usually providing % as an argument to the shell command. For example :
:!psql -f %
I also have a lot of bash shell functions in my .bashrc that I use. For example:
psql-h1 ()
{
/usr/bin/psql -hh1 -d mydb "$#"
}
These bash functions aren't available from :! inside of vim. Is there a way to make them available?
Export your functions. That is:
psql-h1() { /usr/bin/psql -hh1 -d mydb "$#"; }
export -f psql-h1 ### <-- THIS RIGHT HERE
This will make them available to any copy of bash run as a child process, even if it's a noninteractive shell and so doesn't read .bashrc.
An alternative to exporting your functions (which may no reach Vim is there's a non-Bash shell in between; see here for such a case), you can instruct Vim to start an interactive shell, so that your .bashrc is read. Just pass the -i flag to Bash, via Vim's :help 'shellcmdflag'.
:set shcf=-ic
This answer assumes your vim isn't actually using bash to invoke the remote commands - this can be tested by running :!echo $0 in vim.
Specifically for vim, add:
set shell=/bin/bash
to your .vimrc.
In general, there's two strategies I've found to sometimes work when trying to get other programs to invoke my preferred shell:
export SHELL=/bin/bash
in eg. the .profile file, or:
ln -fsn /bin/bash /bin/sh
which updates the sh symlink to point to bash instead.
On many systems (certainly Ubuntu), /bin/sh is a symlink to a sh-compatible shell (such as bash), rather than the sh shell itself. Given this fact, some programs (I've seen this behaviour in GHC) seem to invoke /bin/sh, so changing where it points to will cause the programs to use bash instead.
The accepted answer didn't work for me. I'm going to go with setting shcf, as suggested elsewhere:
:set shcf=-ic
but another solutions is
!source ~/.bashrc && psql ...
Unfortunately, no solution allows the auto-completion for the command I'm creating to work properly. (The auto_completions suggested are for names of files in my current directory, rather than the ones I specified as follows in .bashrc
complete -F _generate_foo_completions foo
So in any new unix variant I come to I'm always hesitating on where to look for the .profile for bash. This can even be true for weird instances of bash running on my own machine.
Instead of searching through the internet each time, is there a way of seeing which .profiles are currently loaded in bash?
Something like
$ source --list-sourced
So, if you're the one to invoke the shell, you could simply do a bash -v; the output of mine starts with
$> bash -v
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# /etc/bashrc
# System wide functions and aliases
# Environment stuff goes in /etc/profile
# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.
....
which gives you a pretty good start on what is happening, and where to look.
If that is not feasible, you'll have to examine the paths that bash specifies it uses (from man bash):
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.
I am trying to get a bash script to run in git bash while specifying a different .bashrc than the one in my home directory (or none at all) however it is proving an impossible task.
To my understanding this should work:
"C:\Program Files (x86)\Git\bin\sh.exe " --rcfile .bashrc --login -i C:/Scripts/myscript.sh
However no matter what I try either the --rcfile file flag will be completely ignored or the script will get parse errors because it is not parsed by bash.
The following are my findings:
--login flag is needed to get the script to be parsed by bash rather than windows command prompt
--rcfile and also --norc are completely ignored if flags --login is used
I have tried every possible combination I think of, including calling the script within my .bashrc file, swapping the flags around, using the -c flag to run the script command and swapping my .bashrc files around to try using the --norc flag instead.
Is this just a result of shitty bash implementation for windows or am I doing something wrong?
Any help on the matter is appreciated.
You can try sourcing your .bashrc inside the script myscript.sh.
source .bashrc
Or
. .bashrc
As far as I can tell, the -i flag is overridden by the fact that you provide a script for bash to run. Your shell isn't actually interactive, so --rcfile is ignored. The only way I can tell to both run a script and source an additional file is to use a non-interactive login shell; however, in that case, you are restricted to using .bash_profile, .bash_login, or .profile, whichever is found first:
bash --login myscript.sh
There is no --loginfile to override the choice of file sourced prior to myscript.sh.
UPDATE: I forgot about BASH_ENV.
export BASH_ENV=.bashrc
bash myscript.sh
I do not know how you would go about adding BASH_ENV to your environment in Git bash.
How can I tell what type my shell is? ie, whether it's traditional sh, bash, ksh, csh, zsh etc.
Note that checking $SHELL or $0 won't work because $SHELL isn't set by all shells, so if you start in one shell and then start a different one you may still have the old $SHELL.
$0 only tells you where the shell binary is, but doesn't tell you whether /bin/sh is a real Bourne shell or bash.
I presume that the answer will be "try some features and see what breaks", so if anyone can point me at a script that does that, that'd be great.
This is what I use in my .profile:
# .profile is sourced at login by sh and ksh. The zsh sources .zshrc and
# bash sources .bashrc. To get the same behaviour from zsh and bash as well
# I suggest "cd; ln -s .profile .zshrc; ln -s .profile .bashrc".
# Determine what (Bourne compatible) shell we are running under. Put the result
# in $PROFILE_SHELL (not $SHELL) so further code can depend on the shell type.
if test -n "$ZSH_VERSION"; then
PROFILE_SHELL=zsh
elif test -n "$BASH_VERSION"; then
PROFILE_SHELL=bash
elif test -n "$KSH_VERSION"; then
PROFILE_SHELL=ksh
elif test -n "$FCEDIT"; then
PROFILE_SHELL=ksh
elif test -n "$PS3"; then
PROFILE_SHELL=unknown
else
PROFILE_SHELL=sh
fi
It does not make fine distinctions between ksh88, ksh95, pdksh or mksh etc., but in more than ten years it has proven to work for me as designed on all the systems I were at home on (BSD, SunOS, Solaris, Linux, Unicos, HP-UX, AIX, IRIX, MicroStation, Cygwin.)
I don't see the need to check for csh in .profile, as csh sources other files at startup.
Any script you write does not need to check for csh vs Bourne-heritage because you explicitly name the interpreter in the shebang line.
Try to locate the shell path using the current shell PID:
ps -p $$
It should work at least with sh, bash and ksh.
If the reason you're asking is to try to write portable shell code, then spotting the shell type, and switching based on it, is an unreliable strategy. There's just too much variation possible.
Depending on what you're doing here, you might want to look at the relevant part of the autoconf documentation. That includes an interesting (and in some respects quite dismal) zoology of different shell aberrations.
For the goal of portable code, this section should be very helpful. If you do need to spot shell variants, then there might be some code buried in autoconf (or at least in one of the ./configure scripts it generates) which will help with the sniffing.
You can use something like this:
shell=`cat /proc/$$/cmdline`
Oh, I had this problem. :D
There is a quick hack, use ps -p $$ command to list the process with PID of the current running process -- which is your SHELL. This returns a string table structure, if you want, you can AWK, or SED the shell out...
The system shell is the thing you see when you open up a fresh terminal window which is not set to something other than bash (assuming this is your default SHELL).
echo $SHELL
Generally, you can find out all the constants defined by running
set
If the output is a lot of stuff then run
set | less
so you can scroll it from the top of the command line or
set > set.txt
To save the output to a file.
Invoking a different interactive shell to bash in your terminal does not mean that your system shell gets changed to something else i.e. your system shell is set to bash although you invoke a csh shell from a bash shell just that one session.
The above means that typing /bin/csh or /bin/python in bash or whatever does not set the system shell to the shell you invoked, at all.
If you really want to see the SHELL constant change then you need to set it to something else. If successful you should see the new shell whenever you open a fresh terminal...
It's old thread but...
In GNU environment You can sh --help and get something like
BusyBox v1.23.2 (2015-04-24 15:46:01 GMT) multi-call binary.
Usage: sh [-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]
Unix shell interpreter
So, the first line is shell type =)
I am trying to use aliases in a non-interactive bash shell. I have defined my aliases in ~/.bashrc and I have set the variable BASH_ENV=~/startUpFile. The contents of the startUpFile are source ~/.bashrc.
I can see that my aliases are recognized, when I execute the alias command. However, if I try to use an alias defined in ~/.bashrc, Bash can't recognized it. It gives me the unknown command error.
With the TCSH shell it is pretty easy to do this because the ~/.cshrc file is always read.
Any ideas how I can do this with a Bash shell?
The command shopt -s expand_aliases will allow alias expansion in non-interactive shells.
.bashrc is only processed by interactive shells.
In addition, aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt. Unless, of course, POSIX mode is invoked by calling the shell with the name sh instead of bash.
People who use aliases a lot often source their .bashrc at the end of their profile so that the aliases are there even for non-interactive shells. This might not be the best way, but it is pretty common.
It's things like this that lead me to believe that in the 21st century we should abandon shell scripts in favor of a full-blown language like Python. It's a lot more predictable.
You have to
shopt -s expand_aliases
in the file pointed to in your BASH_ENV
I had similar issue, in the end, I found out that ~/.bashrc was all I needed.
However, in Ubuntu, I had to comment the line that stops processing ~/.bashrc :
If not running interactively, don't do anything
[ -z "$PS1" ] && return