standardizing prompts across shells in cygwin - cygwin

I'm having a heck of a time standardizing my prompts across the different shells I have installed for cygwin.
Installed shells:
bash (default login shell)
sh
csh (tcsh, actually)
ksh
zsh
My prompt is standardized across bash, csh, and zsh, but I can't get sh and ksh on board.
The prompt I'm looking to use across all shells is similar to the following:
20121216 15:18:04 [shell] # date and time in yellow, shell in red
user#hostname pwd # user#host in green, pwd in yellow
$ # white
I've got it set the way I want it for bash with the following line in /etc/profile:
PS1="\[\e]0;\w\a\]\n\[\e[33m\]\D{%Y%m%d %H:%M:%S} \[\e[31m\][bash]\n\[\e[32m\]\u#\h \[\e[33m\]\w\[\e[0m\]\n\$ "
And I've got it set for csh with the following line in .tcshrc:
set prompt="\n%{\033[33m%}%Y%W%D %P %{\033[31m%}[csh]\n%{\033[32m%}%n#%M %{\033[33m%}%~\n%{\033[0m%}$ "
And I've got it set for zsh with the following lines in .zshrc:
PROMPT="
%{$fg[yellow]%}%D{%Y%m%d} %* %{$fg[red]%}[zsh]%{$reset_color%}
%{$fg[green]%}%n#%m %{$reset_color%}%{$fg[yellow]%}%~%{$reset_color%}
$ "
But I can't seem to set a default prompt for sh or ksh anywhere. I can open both of them and manually set PS1="$ ", but I cannot for the life of me get it to set automatically. The sh prompt looks identical to the bash prompt, and the ksh prompt is gibberish (bc it doesn't like the syntax of PS1 that it's inheriting from bash, I assume).
Things I've tried unsuccessfully:
setting PS1 in /etc/profile (in a case statement reading the shell
name from echo $0)
setting PS1 in .kshrc
setting PS1 in .shrc
setting PS1 in .sh_profile
setting PS1 in .profile
It seems that cygwin just doesn't execute the files listed above when I launch one of those shells. Note that I only ever launch those shells from within bash.
Any ideas? (Sorry for the book, I'm just trying to be thorough.)

The official Korn shell ksh93 will read /etc/profile and ~/.profile on login, in that order.
If ksh is not acting as a login shell it will try to read the file referred to by $ENV, or $HOME/.kshrc if ENV is not set.
Older versions (sun's ksh88 in particular) suffered from a chicken and egg situation because you could only set ENV in ~/.profile, but then you still had to source the file yourself with . $ENV.
Note that ENV and PS1 have to be exported in order to be picked up by ksh instances spawned after login (say, from screen or tmux).

Related

How to reload /etc/environment from shell script

So I have this shell script that checks and then concats an environmental variable to /etc/environment, then reloads the file without having to logout/login:
#!/bin/sh
portvar="PORT=5000"
echo $portvar
grep -q $portvar /etc/environment && echo "EV already in" || echo $portvar >> /etc/environment
set -a; source /etc/environment; set +a;
When I run it, I get the error ./test.sh: 5: ./test.sh: source: not found. However, if I run set -a; source /etc/environment; set +a; directly in the terminal it updates the environmental variable just fine. I have no idea what the set command does, I just found it in another stack overflow question.
Any idea why it runs in the terminal directly but not in the .sh file?
Thanks
/bin/sh on your system is likely some shell that isn't bash and doesn't implement the source command. On my Ubuntu 20.04 system /bin/sh is actually dash.
The source command is not defined by POSIX as part of the shell command language nor is it one of the required special built-in utilities. It's a non-standard feature provided by bash. However, the . command, which does the same thing, is specified by POSIX.
So you can use . instead, e.g. . /etc/environment. Or if you want to keep using source, then you need to have your script run by bash or some other shell that supports it, by changing the shebang line to #!/bin/bash.
There is a tool called checkbashisms that can help you find unintentional uses of bash-specific features in your scripts. When run on your script, it flags this:
possible bashism in foo.sh line 5 (should be '.', not 'source'):

PS1 not setting color

I have a PS1 varible in bash_profile file as
orange=$(tput setaf 166);
yellow=$(tput setaf 228);
green=$(tput setaf 71);
white=$(tput setaf 15);
bold=$(tput bold);
reset=$(tput sgr0);
PS1="\[${bold}\]";
PS1+="\[${orange}\]\u"; # username
PS1+="\[${white}\]#";
PS1+="\[${yellow}\]\h "; # host
PS1+="\[${green}\]\w"; # working directory
PS1+="\[${white}\]\$ \[${reset}\]"; # '$' (and reset color)
export PS1;
When I open the new terminal instance it's showing everything properly except color.
But, when I execute the command
source .bash_profile
the color is working. It disappears if I open a new tab.
But, In a new terminal instance, without executing the source command,
the color works for
export PS1="\[\033[35m\]\t\[\033[m\]-\[\033[36m\]\u\[\033[m\]#\[\033[32m\]\h:\[\033[33;1m\]\w\[\033[m\]\$ "
[
What's the reason for this weird behavior?
In breif, in a new terminal session,
first PS1 is not displaying colors but the second ps1 put in the same bash_profile file is displying it.
But the first one is displaying colors when it is sourced.
Note: I am using mac.
I m also sure that the variable is getting set in bash_profile
but the color is not being set.
You should investigate a little more (yes even more).
In each case you should use printf "%q\n" "$PS1" to see the exact value of the variable PS1 (with escaped unprintable characters). Are you just trying to add the colors to an already set PS1 variable? So, if you get the uncolored output, could that be because your code just wasn't executed so the original value is still set? Then just the PROFILE script isn't executed.
.bash_profile typically only is executed when a login-shell is started. Nowadays many distributions don't get it right and are full of workarounds in this matter, so they often contain .bashrc files which source .bash_profile in their beginning. .bashrc is sourced for each new shell, so effectively, your .bash_profile might well be sourced for each shell as well.
I could guess that your .bashrc first sources .bash_profile and then sets the PS1 to a value like yours, just without the colors. But of course, that's guesswork.
I suspect in the OP's case that using ~/.bashrc rather than ~/.bash_profile to set the colours, is all that is required.
Here is how things work:
There are a number of files involved in setting up your bash environment.
/etc/profile sets the system-wide profile
~/.bash_profile, ~/.bash_login, ~/.profile - These are read by default when bash is invoked as a login shell
~/.bashrc - This is always read unless bash is invoked as sh or bash is invoked as bash --norc
~/.bash_logout - login shell cleanup
~/.inputrc - readline initialisation file.
Which files, and order that these files are read depends on exactly how bash is invoked.
There are a number of cases not all of which are mutually exclusive:
login shell
interactive shell
non-interactive shell
posix mode
bash invoked with stdin connected to network connection (yes
it will know)
bash invoked as sh
bash is invoked with the effective uid/gid not equal to the real uid/gid
You need to be aware of which cases apply to your invocation in order to determine which files will be read.
man bash and search for invocation, for the exact details.
I had installed solarized color scheme/theme for my xterm-256 terminal. It was the one causing the issue. When I change the color scheme, the PS1 is working perfectly.

Is there an alternative for .bashrc for /bin/sh?

I need a script which is run on startup of /bin/sh, similar to .bashrc for /bin/bash. Is there any way to do this?
EDIT:
I tried both /etc/profile and ~/.profile, I wrote echo 'hello world' to both files. None of these are working. When I type sh into the console, nothing pops up.
I am using ArchLinux.
In Arch, /bin/sh is a symlink to /bin/bash, which has quite a few rules about startup scripts, with special cases when called sh :
If bash is invoked with the name sh, it tries to mimic the startup
behavior of historical versions of sh as closely as possible, ...
If you start it from the console, without any command, i.e. as an interactive, non-login shell, you should use the ENV variable :
export ENV=~/.profile
sh
or
ENV=~/.profile sh
When invoked as an interactive [non login] shell with the name sh, bash looks for the variable ENV, expands its value if it is defined, and uses the expanded value as the name of a file to read and execute.
Alternatively you can use the --login option to make it behave like a login shell, and read the .profile file.
sh --login
When invoked as an interactive login shell [with the name sh], or a
non-interactive shell with the --login option, it first attempts to
read and execute commands from /etc/profile and ~/.profile, in that
order
I will assume, as is true on debian-ubuntu-like systems, that your /bin/sh is dash.
For dash, set the environment variable ENV to have the path to the initialization file of your choice. This would be dash's analog to ~/.bashrc.
If you are interested in login shells, dash reads ~/.profile.
As an example, one could add to ~/.profile:
ENV=$HOME/.shinit; export ENV
This would cause dash to read ~/.shinit when an interactive shell starts.
Edit
"I tried both /etc/profile and ~/.profile, I wrote echo 'hello world'
to both files. None of these are working. When I type sh into the
console, nothing pops up."
Those files are only read for login shells. If you just run sh at the command prompt, you are starting an interactive shell.
Documentation
From man dash:
Invocation If no args are present and if the standard input of
the shell is connected to a terminal (or if the -i flag is set), and
the -c option is not present, the shell is considered an interactive
shell. An interactive shell generally prompts before each command and
handles programming and command errors
differently (as described below). When first starting, the shell inspects argument 0, and if it begins with a dash ‘-’, the shell is
also considered a
login shell. This is normally done automatically by the system when the user first logs in. A login shell first reads commands from
the files /etc/profile and .profile if they exist. If the
environment variable ENV is set on entry to an interactive shell, or
is set in the .profile of a login shell, the shell next reads
commands from the file named in ENV. Therefore, a user should place
commands that are to be executed only at login time in the .profile
file, and commands that are executed for every interactive shell
inside the ENV file. To set the ENV variable to some file, place the
following line in your .profile of your home directory
ENV=$HOME/.shinit; export ENV
substituting for “.shinit” any filename you wish.
If command line arguments besides the options have been specified,
then the shell treats the first argument as the name of a file from
which to read commands (a shell script), and the remaining arguments
are set as the positional parameters of the shell ($1, $2, etc).
Otherwise, the shell reads commands from its standard input. [Emphasis added.]
POSIX
From the POSIX standard (hat tip: chepner):
ENV This variable, when and only when an interactive shell is
invoked, shall be subjected to parameter expansion (see Parameter
Expansion) by the shell, and the resulting value shall be used as a
pathname of a file containing shell commands to execute in the current
environment. The file need not be executable. If the expanded value of
ENV is not an absolute pathname, the results are unspecified. ENV
shall be ignored if the real and effective user IDs or real and
effective group IDs of the process are different.

Can you run a script every time /bin/sh is invoked?

With bash, you can set your ~/.bashrc file to run something every time a new bash shell is created. Is it possible to do the same thing with /bin/sh? (This is on Debian, by the way).
For now, I just want to echo 'I am sh' when /bin/sh is invoked. It's easy to do in bash ("echo 'I am bash'" placed at the top of the file).
Thanks!
When starting a login shell of dash, which is /bin/sh on debian-like systems, it will read ~/.profile. If you also want a configuration file read for interactive non-login shells, add the following line to your ~/.profile file:
ENV=$HOME/.shinit; export ENV
Then, with the variable ENV appearing in the environment, the file $HOME/.shinit will be sourced with every new interactive (dash) shell.
You may change the file name specified by ENV to any file name you prefer.
To assure a dash login shell has added ENV to the environment, you may need to logout and log back in, or possibly reboot, depending on your system setup.
Documentation
This is documented in man dash:
A login shell first reads
commands from the files /etc/profile and .profile if they exist. If the environment variable ENV
is set on entry to an interactive shell, or is set in the .profile of a login shell, the shell
next reads commands from the file named in ENV. Therefore, a user should place commands that are
to be executed only at login time in the .profile file, and commands that are executed for every
interactive shell inside the ENV file.
Example
Suppose that we have files set up like:
$ echo "ENV=$HOME/.shinit; export ENV" >>~/.profile
$ cat .shinit
echo FOUND ME
Since I just added the ENV line to the ~/.profile file, ENV is not yet in the environment. If we run dash:
$ dash
$
Nothing happened because this is a non-login shell and ENV is not yet in the environment.
If we start a login shell, ENV is placed in the environment and ~/.shinit is run:
$ dash -l
FOUND ME
If, as a child of that shell, we run an interactive non-login shell, then ~/.shinit will be run because the parent shell created the ENV variable:
$ dash
FOUND ME
The environment created by the login shell above only affects its children. To assure that all interactive dash shells have ENV in their environment may, as mentioned above, require logging out and back in, or a reboot.

Missing gem after changing shell to ksh

my MAC is getting hair-wired after I change console to ksh, and change it back again to /bin/bash
the console prompt is now static bash-3.2 regardless current directory I am in. Meanwhile in .bash_profile I have set # modify console
export PS1="\W > "
rake gem and few others in Ruby are missing, although it was reinstalled again after I run bundle install , but there are subsequent strange issue, e.g. rake command does not hit the right rake file..
Any idea?
Thanks a lot.
The .bash_profile is only run by bash when you first log in. (It only gets run by Terminal if you have Terminal set up to make each shell a "login shell"). If you have commands that you want to get run every time you fire up bash, even if it's not a login shell, you should put them in .bashrc instead. But you can always make a shell be a login shell by running bash --login instead of just bash.
Not sure where your ksh comes from, but note that it doesn't understand '\W' etc in the prompt string, so I would expect you to get a literal '\W' in the prompt instead of the expanded working dir. If you're running ksh as a login shell, it's probably something in the .profile (or /etc/profile, etc.). ksh doesn't have an exact equivalent of .bashrc, but if $ENV is set to a filename after the profile runs, that file is executed as well (even on non-login shells, if ENV is already set when the shell starts). Ksh, of course, ignores .bash_profile and .bashrc.
Since there's no ref to gems in the body of your question (anymore?), you might want to change the question and remove the Ruby tag...

Resources