I am using iTerm2 integrated with tmux. My normal working pattern is to first open up the iTerm2 terminal on my Mac, and then ssh to my dev Virtual Machine.
My dev VM has tmux installed, so that I can re-attach the tmux sessions to my dev VM.
The problem is when the first time I create the tmux session it will source ~/.bashrc with no problem.
But if I clean detach tmux session, and later re-attach those tmux sessions, the ~/.bashrc will not be sourced.
I have included
if [ -f ~/.bashrc ]; then source ~/.bashrc; fi
in ~/.bash_profile, .profile, .bash_login.
And also included
set-option -g default-command "exec /bin/bash"
to ~/.tmux.conf
As is implied by the verb "re-attach", your tmux session (and with it the Bash shell that runs in it) is kept running on your dev machine when you disconnect, so that you can later reconnect to the very same session. (That's the main feature of tmux: Normally, a shell is directly connected to your terminal or SSH session, so when you close / disconnect it, the shell has nothing to read from and output to, so it will have to exit. tmux provides a virtual terminal in between, so the shell has something to hang onto (even if nobody sees the output and nobody currently inputs anything), and tmux handles the session management.)
Applications (like Bash and also Vim) usually only read their configuration on startup. As Bash is kept running (you can verify that via ps -o etime --pid $$), it won't notice that you're reconnecting via tmux, and has no reason to reload its config - everything should still be defined and preserved within the tmux session. If you need to reload a (changed) configuration, you have to do this explicitly (source ~/.bashrc), or open up a new shell.
Related
Does anyone know any way of doing this? The help would be greatly appreciated, I've been beating my head over this one for a while now, and I can't seem to find any way to get scripts to auto-start and display in the foreground as they would if I had manually started them.
what i want to do is basically just power on the vm, let it boot, then watch the script run and echo results to the console or whatever the script would normally display if ran manually
I've been able to use Cron and systemd to run the script I would like to run at startup, but I cannot figure out any way to get these scripts to run in the screen, as they would if I had typed ./startup_script.sh
i am currently testing everything in a headless Debian 11 vm. Auto login as root is already enabled. i just need to complete this last step but i don't know how to do.
You can fire up a tmux session and send keys it to start a script like this:
tsid="session_name"
my_script="/home/script.sh"
# create new tmux session
tmux new-session -d -s ${tsid}
# launch the script in the tmux session
echo "launching script in a tmux session called ${tsid}"
tmux send-keys -t ${tsid} "${$my_script}" 'C-m'
I do something similar to start a "quad-pane" to my raspberry pi devices. I can send commands to each pane via ssh without looking at the screen I am sending commands to. I can send commands to the panes from any ssh session without actually connecting to a gui, or being in the "session". This way, another machine can have that session up on a monitoring display and I can momentarily ssh over a command to the host and it will show over there without ever actually connecting to the window. The panes can run scripts and and have the output on the each respective screen/pane waiting for me to connect later and look at it. Every now and then I'll pull up my quad feed to see what's happening... then disconnect and leave it all running.
# function to send an arbitrary command to a tmux pane
# arg1: full id of pane, e.g. "pi4-host01:quad-feed.0"
# arg2+ command(s) to send to pane
tmux_send_command_to_pane_id() {
local tpid cmd
tpid="${1:-0}"
cmd="${#}"
echo "cmd to send to pane: ${tpid}: ${cmd}"
tmux send-keys -t "${tpid}" "${cmd}" 'C-m'
}
If you pair something like this with cron or systemd, i'd imagine you could get to your goal relatively quick. It does depend on installing tmux. I know others use screen, but I have become a fan of tmux for whatever reason.
A nice answer on systemd scripts here -> https://unix.stackexchange.com/a/47715/376937
Here is another question that may help as well:
Tmux command to run shell command on active pane?
I am running a server with Ubuntu 14.04 using nodejs with
npm start
command.
I start tmux session with
tmux
command, then do
npm start
and finally do
ctrl+d
to detach.
But ctrl+d would not work for me. Whatever I am using, it only detaches me from the session if I stop all the processes.
It is also same problem when I am trying to detach from session with mongod running.
Any ideas?
PS: running ctrl+a+d does not work either.
When issuing a tmux command, you need to first use the prefix key combination. By default, this is C-b (ctrl+b).
If the default prefix isn't working, it's possible that you changed it or, if you're using someone else's .tmux.conf, they may have changed it. You can run tmux list-keys | grep send-prefix from your shell to determine what the current prefix is.
So, in order to detach from a running session, you'd type C-b d.
I am using my laptop via shell terminal to log on school’s server to run a
Matlab session. The session will take about 10 hours and I want to close my
laptop, go home, have dinner, and re-engage the shell terminal to check the
progress of my Matlab session.
From this link I know I should use nohup nohup to keep my terminal alive,
but I meet the following problem. Here is a screenshot of my shell after I start
running Matlab session:
where a = cv000_29590 is the respond from the Matlab. It should keep running
until cv999999 and take about 10 hours.
The problem is, this shell is not interactive anymore. I can’t enter anymore
commands, that is, I have no where to enter nohup commend to keep my SSH
session alive.
It's not really possible after you've already started a session. But for new sessions you can do the following:
Add the following to the top of your .bash_profile:
if [ -z "${PS1}" ] ; then
return
fi
if [ "${TERM}" != "screen" ] ; then
export HOSTNAME
exec screen -xRR
fi
function new {
u=${1:-$USER}
test ${u} = ${USER} && screen -t ${u}#${HOSTNAME} || screen -t ${u}#${HOSTNAME} su --login ${u}
}
Put the following content into .screenrc:
escape ^bb
shell -$SHELL
termcapinfo xterm ti#:te#
hardstatus lastline "%-Lw[%n%f %t]%+Lw%<"
screen -t ${USER}#${HOSTNAME}
These are mostly my own customizations of screen. The most important of which is that I set the screen escape character to CTRL-b instead of the default CTRL-a so I can still use CTRL-a in bash to go to the beginning of a line.
Use CTRL-b c to create shells in new windows (or just type new at the bash prompt to use the function). And use CTRL-b d to detach your session and leave it running. Next time you login, you'll be reattached to your session and everything will be as it was. Use CTRL-b n to cycle through the windows you've created. If you don't want to multiple windows, you don't have to, just use the ability to leave a session running and reattach later.
The directory where a tmux session is started in will be the directory that new windows start at. How do I change this starting directory without closing the tmux session?
The way to do this is to detach from the session (^b d with the default keybindings) and then specify a different directory when you reattach to it. When attaching to a session, use the -c flag to specify the working directory. Here's an example:
$ tmux list-sessions
tmuxwtfbbq: 3 windows (created Tue Apr 5 14:25:48 2016) [190x49]
$ tmux attach-session -t tmuxwtfbbq -c /home/chuck/new_default_directory
This setting will be persisted - after you've reset the working directory, you won't need to keep specifying it every time you reattach to the session.
For the record, I'm on tmux version 2.0 (though I don't think it matters - I couldn't find anything about adding a -c option to the attach-session command in the change logs so I assume it's been there for quite a while).
Chucksmash's answer is a good one, but it can also be achieved without using the session if you like. The command attach-session is also available in the tmux command prompt; and the target session can be specified as the "current" session using a dot.
attach-session -t . -c /path/to/new/directory
Here's how you can change the tmux session's working directory without detaching the session, and without needing use to the <prefix> keystrokes:
(Option 1) Enter the directory at tmux command prompt:
tmux command-prompt "attach -c %1"
...will open a command prompt, then you type the working directory you want ~/my/dir and press ENTER
(Option 2) Provide the directory on the in-pane command line:
# Execute this in one of the shell panes of within your tmux session:
tmux command-prompt -I $PWD -P "New session dir:" "attach -c %1"
With this approach, the prompt for new-directory is pre-populated with the current dir of the pane which launched the command. Of course you can substitute anything else for $PWD if you please.
Want a shell function?
I have added this to my shell initialization:
# Change the current directory for a tmux session, which determines
# the starting dir for new windows/panes:
function tmux-cwd {
tmux command-prompt -I $PWD -P "New session dir:" "attach -c %1"
}
With all of these options, any future new windows will start in the given dir.
Note: attach, attach-session, and a are all aliases for each other. The tmux command-prompt has many other powers, it's worth reading the man page
use attach-session -c from command prompt or in a binding.
I have bindings to use the current directory automatically, using the provided pane_current_path var.
I have this bound to M-c, to update the current path.
# tmux.conf
# set default directory for new windows in this session to current directory:
bind M-c attach-session -c "#{pane_current_path}"
Similarly, when I just want another window in the current directory without changing the default, I have a binding on C:
# tmux.conf
# open a new window in the current directory
bind C new-window -c "#{pane_current_path}"
My bindings:
c: open a new window in session default directory [default binding]
C: open a new window in current directory
M-c: set session default directory to current directory
Happy Tmuxing!
The default working directory can be changed from the command line like this:
TMUX= tmux -C attach -c directory -t session </dev/null >/dev/null
Compared to command-prompt, for example, this has the advantage that no interactive prompts or confirmations are produced, so this can be run in a script. Unsetting TMUX allows attaching from inside a session, the option -C turns on control mode for non-interactive use and redirecting from /dev/null causes the client to detach immediately, while still updating the default directory. Redirecting the output is not necessary, but it suppresses messages.
I'm running Ubuntu and use gnome-terminal and would like to run tmux in such a way that it can use all of the gnome-session environment in the same way opening a new terminal window would. E.g. using passphrase-less ssh.
The issue seems to be the process hierarchy...
In a new window of gnome-terminal:
$ pstree -ps $$
init(1)───lightdm(1825)───lightdm(18486)───gnome-session(18552)───gnome-terminal(18626)
Once I enter a new tmux session (even in the above terminal window:
$ pstree -ps $$
init(1)───tmux(15798)───bash(21770)
tmux appears to be a direct child of init and not in the session's process hierarchy. Is there a way to get it to be created as a child of gnome-session?
EDIT: Great answer below (the accepted one)! However I thought I'd include a function I wrote since receiving the answer to update all child bash processes of tmux to the latest environment:
#!/bin/bash
tmup ()
{
echo -n "Updating to latest tmux environment...";
export IFS=",";
for line in $(tmux showenv -t $(tmux display -p "#S") | tr "\n" ",");
do
if [[ $line == -* ]]; then
unset $(echo $line | cut -c2-);
else
export $line;
fi;
done;
unset IFS;
echo "Done"
}
The tmux server calls daemon(3) to detach itself from the process that started it (i.e. the initial tmux client). This is not optional so the server will always be reparented to PID 1 (e.g. init) after the double-fork-and-middle-exit done by daemon(3).
In general, it should not be important that the tmux server is no longer directly “connected” to gnome-session though the parentage of (surviving) processes.
In the case of ssh, the ability to use a key without having to retype its passphrase relies on access to an ssh-agent process. Instances of ssh look for the SSH_AUTH_SOCK environment variable to know where to contact an ssh-agent that can supply keys for it. gnome-session probably arranges to start an ssh-agent and populate its environment with the appropriate SSH_AUTH_SOCK value. This environment is inherited from parent to child as your various processes are started. In this way, the tmux server will also inherit the SSH_AUTH_SOCK value (from the initial tmux client, which got it from a shell, which got it from gnome-terminal, which got it from gnome-session).
A problem occurs, however, when you attach to a tmux session that was started from a different environment. Consider the following scenario that is hinted at by the fact that the PID of your tmux server is lower than that of your gnome-session:
Log in to a GUI session.
gnome-session starts an ssh-agent and configures SSH_AUTH_SOCK=foo in its environment; this value will be inherited by all of its future children.
You start a tmux server (via a shell and gnome-terminal).
The tmux server inherits SSH_AUTH_SOCK=foo; it will be passed on to its children (e.g. a shell running in a tmux session).
You disconnect from your tmux session and log out of your GUI session.
The tmux server and its children still have SSH_AUTH_SOCK=foo, but that value is probably no longer valid (when gnome-session is winding down, it probably killed the ssh-agent that it started).
Later, you log back in to a GUI session.
This time gnome-session sets SSH_AUTH_SOCK=bar and passes it along to its children.
You reconnect to your tmux session.
At this point, you have SSH_AUTH_SOCK=bar “outside” tmux and SSH_AUTH_SOCK=foo “inside” the session. This is the probably where you run into problems.
Effectively, since the tmux server has outlived the original GUI session, any environment variables it initially inherited that were specific to that session are potentially invalid (unless they happen to use exactly the same values the next time you log into a GUI session).
Luckily, tmux has a feature for handling this scenario. The update-environment session option specifies a list of environment variables that are copied into (or removed from) the “session environment” when a client creates or attaches to a session. SSH_AUTH_SOCK is a part of the default value of this option, so it is updated when you reattach. But, tmux is only able to update its “session environment” (which will be inherited by any new children of that session).
Unfortunately, tmux has no way to update any existing processes that are a part of that session (indeed, this is impossible, short of debugging tools that can tinker with the internals of already running processes). So, any existing shells running in windows/panes after the above scenario will probably be using an invalid SSH_AUTH_SOCK. ssh will not complain about the invalid value, it will just prompt you for the appropriate key’s passphrase.
What you might try doing is extracting the value of SSH_AUTH_SOCK from the session environment and incorporating it into the pre-existing shells from your old session with a command like this:
SSH_AUTH_SOCK=$(tmux show-environment | awk '/^SSH_AUTH_SOCK=/ { sub(/.*=/,""); print }')
If you are having issues related to other environment variables, then you may need to add them to update-environment (e.g. set-option -ga update-environment ' FROBNIZ' in your ~/.tmux.conf) and do something similar to copy the values into any existing shells after you reattach from a different context.