Safely exec tmux upon login - shell

I would like to execute tmux upon logging into a shell for my user. I am using fish, but I think this question is relevant to any shell. So far, I've accomplished this by following the advice in this question: https://askubuntu.com/questions/560253/automatically-running-tmux-in-fish, specifically, adding the following line to my config.fish:
test $TERM != "screen"; and exec tmux
However, I have one major issue with this approach, and that is if tmux fails to start, perhaps if I've introduced a syntax error in my .tmux.conf file, the shell process immediately exits, booting me out of the session.
Is there a way to automatically run tmux in new shell executions whereby I can:
Catch errors and fallback on a "plain" shell execution (i.e. just fish without tmux)
Not have to exit a login twice - once to quit tmux then again to quit fish
?

I imagine tmux exits with a non-zero (i.e. failing) status if there's configuration errors, so you could presumably ditch the exec and exit manually, like
if test $TERM != "screen"
tmux
and exit
end
However, do keep in mind that fish always sources all of its config files, so you'll want to wrap this inside if status --is-login or similar.

This works for me:
if status --is-login
source $HOME/.config/fish/login.fish
tmux; and exec true
end
Obviously you may or may not have a login.fish file. I like to keep my config.fish lean by putting code that might not be needed for the current session in separate files so I've also got a interactive.fish script

Related

Is it possible to execute a bashscript after kill a terminal?

I know that have a file called .bash_profile that executes code (bashscript) when you open a terminal.
And there is another file that is called .bash_logout that executes code when you exit the terminal.
How I would execute some script when terminal is killed?
(.bash_logout do not cover this when terminal is killed).
How I would execute some script when terminal is killed?
I interpret this as "execute a script when the terminal window is closed". To do so, add the following inside your .bashrc or .bash_profile:
trap '[ -t 0 ] || command to execute' EXIT
Of course you can replace command to execute with source ~/.bash_exit and put all the commands inside the file .bash_exit in your home directory.
The special EXIT trap is executed whenever the shell exits (e.g. by closing the terminal, but also by pressing CtrlD on the prompt, or executing exit, or ...).
[ -t 0 ] checks whether stdin is connected to a terminal. Due to || the next command is executed only if that test fails, which it does when closing the terminal, but doesn't for other common ways to exit bash (e.g. pressing CtrlD on the prompt or executing exit).
Failed attempts (read only if you try to find and alternative)
In the terminals I have heard of, bash always receives a SIGHUP signal when the window is closed. Sometimes there are even two SIGHUPs; one from the terminal, and one from the kernel when the pty (pseudoterminal) is closed. However, sometimes both SIGHUPs are lost in interactive sessions, because bash's readline temporarily uses its own traps. Strangely enough, the SIGHUPs always seem to get caught when there is an EXIT trap; even if that EXIT trap does nothing.
However, I strongly advise against setting any trap on SIGHUP. Bash processes non-EXIT traps only after the current command finished. If you ran sh -c 'while true; do true; done' and closed the terminal, bash would continue to run in the background as if you had used disown or nohup.

fish shell login commands keep running on screen or tmux session after login

I've just switched to fish-shell
And I've used the instructions of How do I run a command every login? What's fish's equivalent to .bashrc?
Which means I've moved the commands which i prefer to run upon login from .bashrc to ~/.config/fish/config.fish
But right now the commands keep running if i open screen or tmux session ! but before while i were using the default shell that's was never happens (meant that the commands were only run during the login and never re-run in screen session)
How to avoid this?
Thanks in advance.
You can test for the TERM environmental variable to see if your shell is running in such a session. Both screen and tmux by default set it to 'screen'.
if not string match --quiet -e $TERM 'screen'
<your startup scripts>
end
Note that other useful indicators are whether a shell is interactive or a login shell. You can use status --is-interactive and status --is-login to check for these two states.
In your specific case, a check for login shell might be what you are looking for:
if status --is-login
<your startup scripts>
end
See https://unix.stackexchange.com/questions/38175/difference-between-login-shell-and-non-login-shell for an explanation.

How to ssh into a shell and run a script and leave myself at the prompt

I am using elastic map reduce from Amazon. I am sshing into hadoop master node and executing a script like.
$EMR_BIN/elastic-mapreduce --jobflow $JOBFLOW --ssh < hivescript.sh . It sshes me into the master node and runs the hive script. The hivescript contains the following lines
hive
add jar joda-time-1.6.jar;
add jar EmrHiveUtils-1.2.jar;
and some commands to create hive tables. The script runs fine and creates the hive tables and everything else, but comes back to the prompt from where I ran the script. How do I leave it sshed into hadoop master node at the hive prompt.
Consider using Expect, then you could do something along these lines and interact at the end:
/usr/bin/expect <<EOF
spawn ssh ... YourHost
expect "password"
send "password\n"
send javastuff
interact
EOF
These are the most common answers I've seen (with the drawbacks I ran into with them):
Use expect
This is probably the most well rounded solution for most people
I cannot control whether expect is installed in my target environments
Just to try this out anyway, I put together a simple expect script to ssh to a remote machine, send a simple command, and turn control over to the user. There was a long delay before the prompt showed up, and after fiddling with it with little success I decided to move on for the time being.
Eventually I came back to this as the final solution after realizing I had violated one of the 3 virtues of a good programmer -- false impatience.
Use screen / tmux to start the shell, then inject commands from an external process.
This works ok, but if the terminal window dies it leaves a screen/tmux instance hanging around. I could certainly try to come up with a way to just re-attach to prior instances or kill them; screen (and probably tmux) can make it die instead of auto-detaching, but I didn't fiddle with it.
If using gnome-terminal, use its -x or --command flag (I'm guessing xterm and others have similar options)
I'll go into more detail on problems I had with this on #4
Make a bash script with #!/bin/bash --init-file as the shebang; this will cause your script to execute, then leave an interactive shell running afterward
This and #3 had issues with some programs that required user interaction before the shell is presented to them. Some programs (like ssh) it worked fine with, others (telnet, vxsim) presented a prompt but no text was passed along to the program; only ctrl characters like ^C.
Do something like this: xterm -e 'commands; here; exec bash'. This will cause it to create an interactive shell after your commands execute.
This is fine as long as the user doesn't attempt to interrupt with ^C before the last command executes.
Currently, the only thing I've found that gives me the behavior I need is to use cmdtool from the OpenWin project.
/usr/openwin/bin/cmdtool -I 'commands; here'
# or
/usr/openwin/bin/cmdtool -I 'commands; here' /bin/bash --norc
The resulting terminal injects the list of commands passed with -I to the program executed (no parms means default shell), so those commands show up in that shell's history.
What I don't like is that the terminal cmdtool provides feels so clunky ... but alas.

BASH: Shell Script as Init Script

I have a shell script that calls a java jar file and runs an application. There's no way around this, so I have to work with what I have.
When you execute this shell script, it outputs the application status and just sits there (pretty much a console); so when something happens to the program it updates the screen. This is like with any normal non daemonized/backgrounded process. Only way to get out of it is ctrl-c, which then ends the process altogether. I do know that I could get around this by doing path_to_shell_script/script.sh &, which would background it for my session (I could use nohup if I wanted to logout).
My issue is, I just don't know how to put this script into a init script. I have most of the init script written, but when I try to daemonize it, it doesn't work. I've almost got it working, however, when i run the initscript, it actually spans the same "console" on the script, and just sits there until i hit ctrl-c. Here's the line in question:
daemon ${basedir}/$prog && success || failure
The problem is that I can't background just the daemon ${basedir}/$prog part and I think that's where I'm running into the issue. Has anyone been successful at creating an init script FOR a shell script? Also this shell script is not daemonizable (you can background it, but the underlying program does not support a daemonize option, or else I would have just let the application do all the work).
You need to open a subshell to execute it. It also help to redirect its output to a file, or at least /dev/null.
Something like:
#!/bin/bash
(
{ daemon ${basedir}/$prog && success || failure ; } &>/dev/null
) &
exit 0
It work as follows ( list ) & in a background subshell. { list } is a group command, it's used here to capture all the output of your commands and send it to /dev/null.
I have had success with initially detached screen sessions for running things like the half life server and my custom "tail logfile " bash scripts.
To start something in the background:
screen -dmS arbitarySessionName /path/to/script/launchService.sh
To look at the process:
# screen -r arbitrarySessionName
Hope you find this useful, gl!

Run script before Bash exits

I'd like to run a script every time I close a Bash session.
I use XFCE and Terminal 0.4.5 (Xfce Terminal Emulator), I would like to run a script every time I close a tab in Terminal including the last one (when I close Terminal).
Something like .bashrc but running at the end of every session.
.bash_logout doesn't work
You use trap (see man bash):
trap /u1/myuser/on_exit_script.sh EXIT
The command can be added to your .profile/.login
This works whether you exit the shell normally (e.g. via exit command) or simply kill the terminal window/tab, since the shell gets the EXIT signal either way - I just tested by exiting my putty window.
My answer is similar to DVK's answer but you have to use a command or function, not a file.
$ man bash
[...]
trap [-lp] [[arg] sigspec ...]
The command arg is to be read and executed when the shell
receives signal(s) sigspec.
[...]
If a sigspec is EXIT (0) the command arg is executed on
exit from the shell.
So, you can add to your .bashrc something like the following code:
finish() {
# Your code here
}
trap finish EXIT
Write you script in "~/.bash_logout". It executed by bash(1) when login shell exits.
If you close your session with "exit", might be able to something like
alias endbash="./runscript;exit" and just exit by entering endbash. I'm not entirely sure this works, as I'm running windows at the moment.
edit: DVK has a better answer.

Resources