The excellent answer to the question How do I define an Emacs List function to spawn a shell buffer with a particular command executed in the shell weirdly does not work in a Gnu "screen" session. In the context of a screen command, instead of the command I tell it to execute,
echo 'test1'\n
, Emacs is called recursively! The would-be shell buffer contains the familiar "emacs: Terminal type "dumb" is not powerful enough to run Emacs" message.
How can I make this work? Here's what I did:
On the command line:
~ srn#basil{1}% screen -s run-emacs2
Here is the shell script run-emacs2:
#!/bin/bash
EMACS=/usr/bin/emacs23-x
export NO_AT_BRIDGE=1 ## suppress annoying gtk>2 warning
exec "$EMACS" -nw --load init.el.test -f spawn-shell
NOTE: If on the command line I say:
~ srn#basil{1}% run-emacs2
...everything works fine. The problem appears to be some interaction with Gnu screen.
Here is init.el.test (almost verbatim from the answer linked above):
(defun spawn-shell ()
"Invoke shell test"
(pop-to-buffer (get-buffer-create (generate-new-buffer-name "gzo")))
(shell (current-buffer))
(process-send-string nil "echo 'test1'\n"))
It is expected behavior. According to the screen manual, the -s option is where to look:
-s program
Set the default shell to be program. By default, screen uses the value of the environment variable $SHELL, or /bin/sh if it is not defined. This option is equivalent to the shell command (see Shell).
The screen program sets the $SHELL variable to program (as part of opening a new window), and it is inherited in the subprocess, which in turn runs whatever $SHELL happens to be. Since you do not want that, the fix would be to modify the emacs script to reset $SHELL back to /bin/sh before running a "shell".
Related
Suppose I have this in my .profile
export VALUE=x:$VALUE
Then when I start a terminal and do
$ printenv VALUE
x:
the result is what is expected, i.e., VALUE is equal do x:.
Also if I keep launching bash like this
$ printenv VALUE
x:
$ bash
bash-3.2$ printenv VALUE
x:
bash-3.2$
the result is what is expected too.
However, if I start a terminal and launch tmux instead, I get
$ printenv VALUE
x:
$ tmux
$ printenv VALUE
x:x:
and the final VALUE is not equal do x:.
How can I launch tmux so that this does not happen, and it behaves like a fresh bash session?
I am on macOS 10.12.6 (Sierra)
Thanks
There are several reasons why your ~/.profile happens to be sourced more than once.
One would be that tmux is started in a way so that it behaves like a login shell. As such, it will source the ~/.profile naturally (see man bash at INVOCATION). You can start tmux as a login shell by providing the option -l. You didn't mention giving this explicitly, so I guess you didn't, but maybe it was implicitly passed to tmux by some alias or similar. You might want to double check on this (enter type tmux for instance).
The more probable reason is that tmux just starts a shell which then assumes that it is a login shell and thus sources ~/.profile. This in a way is also correct, because starting a terminal muxer can be seen as the process of logging in. More on this can be found here: https://superuser.com/a/970847/153009
The third possibility (which was the reason in my case when I tried to reproduce your case) is that your ~/.bashrc sources your ~/.profile intentionally and explicitly. Although this is against the original design, one finds this very often. Obviously it often solves ugly issues with missing executions of invocation scripts.
You can check for this by giving out ${BASH_SOURCE[*]} in the beginning of the ~/.profile (redirect it to a file to be sure you can see it later).
Because of problems with this, I have the following script snippet in each of my invocation scripts (.bashrc, .profile, etc.):
(
echo "$(date): .profile: $0: $$"; pstree -lp $PPID 2>/dev/null
echo "BASH_SOURCE: ${BASH_SOURCE[*]}"
echo "FUNCNAME: ${FUNCNAME[*]}"
echo "BASH_LINENO: ${BASH_LINENO[*]}"
) >> ~/var/log/config-scripts.log
(Adjust the name .profile in the first line according to the script name of course.)
It seems there is no way to avoid tmux from starting its own shell without inheriting the environment variables of the shell where tmux is called. This means that startup shell scripts must take care if they are running inside tmux. For example, in bash, this can be done
if [ -n "$TMUX" ];
then
echo Inside tmux
else
echo Outside tmux
fi
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
I want to run a script called tuxsay that combines fortune and cowsay to have tux say some words of wisdom. I made an alias in by .bash_aliases calling it tuxsay and executing the script
FORTUNE= $(fortune)
cowsay -f tux $FORTUNE
I then have a script that will spawn a new terminal and I want it to output the results of my first script then allow me to work in the terminal, something like
xterm -e "tuxsay&"
So how can I spawn a new terminal use cowsay then allow me to work in it?
Specifics: I have a startup script that will spawn applications that I typically use, and I want it to spawn a terminal that runs my tuxsay script then allows me to work. I am on Ubuntu 12.04 LTS and am running dwm 6.0
Why not just add your command to your .bashrc file? Then it will be run every time a new interactive shell is started. You can test if the $TERM variable contains "xterm", and make your output conditional upon that. e.g. add the following line to the end of .bashrc:
[[ "$TERM" =~ xterm ]] && tuxsay
Update
While I think the above is still probably the most useful general answer, I noticed a few more things:
tuxsay is a bash alias. bash aliases are only understood within bash itself, but when you pass a command to xterm -e, that command is executed directly by the xterm without any bash involvement. The system won't be able to find and execute a file called "tuxsay" and will fail.
If executed from bash, the & character will put tuxsay command (alias) in the background, but this doesn't really help here. What you need is a new shell to start up once tuxsay is done.
Be careful with .bash_aliases. I noticed on my Redhat-based system that aliases placed in this file were not working, because .bash_aliases file is not sourced in. (My Bash aliases don't work) So it looks like .bash_aliases is sourced by default from Ubuntu-based systems, but no guarantees for others.
With the above in mind, if you definitely want tuxsay to run on a per-xterm basis – i.e. you want to specify this on the xterm command line – you could do the following one-liner:
xterm -e 'cowsay -f tux $(fortune); bash'
This passes the compound command cowsay -f tux $(fortune); bash to xterm. This compound command consists of two commands: first do the cowsay thing, then start bash.
You could also put these two commands in a shell script and pass the shell-script to xterm.
I'm using W32 GNU Emacs 24.1.50.1 with Cygwin bash 3.2.51. I know that this combination is very troublesome (see EmacsWiki and Cygwin list). However the problem I want to solve now is not confined to Cygwin. I got the issue with MinGW as well. So, the problem is:
In Emacs start a shell via M-x shell provided you have set up the variables shell-file-name and explicit-bash-args appropriately (see e.g. here). Then issue a command which expects stdin input, e.g. cat. To cancel out of cat you can usually type Ctrl-D once and you return to the shell prompt. In W32 emacs when you do this (or even when you issue explicitly M-x comint-send-eof) the cat command gets exited and the bash shell quits as well.
I tried to increases bash's "resilience' by setting the environment variable IGNOREEOF to, say, 5, but then a single Ctrl-D results in the following output
$ Use "exit" to leave the shell.
$ Use "exit" to leave the shell.
$ Use "exit" to leave the shell.
$ Use "exit" to leave the shell.
$ Use "exit" to leave the shell.
$ exit
Process shell finished
and, of course, the bash has exited again. This problem only happens when the shell runs in W32 emacs - Cygwin bash through the Cygwin tty window and MinGW bash through its own MinTTY work fine.
Why is this happening in W32 Emacs and how can I just exit the running subcommand (e.g. cat) when using W32 Emacs without exiting the bash shell?
The notion of tty like you expect it to behave doesn't really exist in the W32 worl. If you want to see this Unixy behavior, you need not only to run a Cygwin program but that Cygwin program needs to talk to another Cygwin program (Emacs, terminal, you name it). IOW you'll only get that with the Cygwin version of Emacs.
The GNU Emacs FAQ for MS Windows notes that this issue exists for any sub-process in the shell buffer. So it affects the DOS command line as well (but of course you don't usually use Ctrl-D in DOS, so it's not so noticeable). No workaround is suggested in the FAQ, so I'm guessing that there's no easy fix.
Usually you can use Ctrl-Z as well as Ctrl-D. Take a look at this note:
http://ignaciopp.wordpress.com/2009/07/02/emacs-shell-workaround-for-killing-input-in-windows-version/
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 =)