Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Be Careful Using Tmux and Environment Variables (aj.codes)
258 points by todsacerdoti on March 4, 2023 | hide | past | favorite | 113 comments


This is something to watch out for especially if you're switching from screen to tmux.

When you start a screen session, it will always copy the environment from your shell. When you start a second screen session, it will inherit a possibly different environment.

But tmux, on the other hand, spawns a tmux server when you first start a session. It'll copy the environment from your shell. However, from that point onwards, new sessions will use the environment from the server and will not copy the environment from your shell.

I like screen's behavior more. A frequent use case is to start a long-running command as a sort of ad-hoc background job. That's really easy with screen (just run screen and run your command, it will always use the parent shell's environment) but relatively easy to screw up with the environment when done with tmux. It kind of works only if you don't have a tmux server already running.


I have tried on multiple occasions to migrate to tmux (because gestures vaguely "it's the future", screen's codebase is ancient and can still connect directly to a serial port etc), but I just don't like the primitives that tmux gives you ((servers,) sessions, windows, panes).

I use a nested setup with screen where each level of nesting has a different escape key, this works really well when I want an inner screen to be on a different machine.

  screen '-e^Zz' -S meta
and then inside that one

  screen '-e^Oo' -S project1
and for a session on a remote machine

  mosh some_server -- screen '-e^Oo' -S remote_session_name

I haven't figured out a way to get this to work well with tmux, because the local tmux server doesn't know about the remote tmux sessions. Whereas with screen, screen doesn't need to know or care about that.

(edit: I use shell aliases, I don't type out the '-e^Oo' etc every time)


> screen's codebase is ancient and can still connect directly to a serial port

That particular feature is pretty important to me, and it would suck if it got removed. Just because a codebase is ancient doesn't mean it's useless.


Embedded Linux user? We used screen & minicom extensively in my unis satellite lab


I'm looking to skip tmux and migrate straight from screen to zellij instead, since it's also modern. I don't have many problems with screen, but lack of full color support (for vim) and wanting more terminal control codes (hyperlinks, text underlines, sixel, etc) speak in favour of using a more modern solution.


I want to love zellij but can't get over how it binds its own actions to practically every key (vs screen/tmux which take just one, the prefix). Do people who use it not use any programs that use control or alt keys?


This can be changed: I use zellij and just rewrote its config file to place almost all the keys in a single mode, basically 1-1 with tmux.

That said, I must admit that zellij doesn't add a whole lot to my workflow relative to tmux. I think I'm just easily distracted by the new-and-shiny.


I also trying to come to terms with this, mostly need to design new custom key settings.

Zellij has Lock interface, default Ctrl+G, which you can use and in that mode it only takes that one key, but it's a bit different from how screen works.


Yeah, but that's more than twice as many keypresses now.


I recommend using tmux mode and adding its keybind to locked mode, that way you get the same key interactions as tmux itself. Sadly, zellij doesn't offer the same options for which key that will be (in screen and tmux I like using C-] cause it's usually unused, but you can't use that one in zellij)


Thanks for pointing out zellij [0]. I wasn't aware of it and am really glad to have read about it.

It's odd. A couple of days ago I watched Tristam Oaten's No Boilerplate video "Oxidise Your Life" [1] and it left me thinking about how Rust is moving some programmers to rewrite tools in Rust and, while at it, adding modern features. It's nice to see that.

[0] https://zellij.dev/screencasts/

[1] https://www.youtube.com/watch?v=dFkGNe4oaKk


I was quite satisfied with tmux but this issue (and one other) really drove me to seek an alternative like zellij so bad, but just couldn't settle on it for one reason or another. Instead I ultimately found refuge in kitty term which as a whole emulator is an overkill, but it's a great replacement and mostly as customizable. It does a good job with windowing - I particularly like the xmonad style window size switching. But there are still some parts of the tmux ecosystem I miss, like tmuxinator and the extracto plugin but otherwise most of my needs have been met, and the speed is a welcome bonus. So, can definitely recommend kitty as a good tmux alternative.


> screen to zellij instead

FFS. Can't we, at some point, be done with wheel re-invention?


Wait until you find out how many people in the 21st century are still iterating on the idea of the wheel itself. Imagine if nobody tried reinventing wheels since they were first introduced and you have your answer.


> Can't we, at some point, be done with wheel re-invention?

You do realize how much of technology and coding is literally re-writing things constantly until they work for [insert stakeholder here]. Right?


i do exactly that with tmux. the primary difference is that don't nest tmux locally, but each tmux session is on a different computer, so they all just need their local config where the escape key is specific to the computer.

why does the local tmux server need to know about the remote tmux session?


I just have one level and search function.

C-b s gets me graphical(via rofi + some scripting) searchable list of windows, in rare cases where I'd need tens of them.

But it took me a while to make tmux keybindings that are fast & convenient, screen defaults (aside from C-a that collides with bash/emacs) on keybindings are way better.


> I haven't figured out a way to get this to work well with tmux, because the local tmux server doesn't know about the remote tmux sessions. Whereas with screen, screen doesn't need to know or care about that.

I'm missing something here. Why does tmux need to know or care?


I use backtick, hen two back ticks, then four. Only rarely have to go to eight backticks. :)


I occasionally open tmux on a remote machine from within a local tmux.

Using c-bb to get to the nested one doesn't seem that bad to me as long as it's only 2-deep.

But why not just change the escape key on each machine's .tmux.conf?


I can't figure out an use case for your setup, can you help a bro out?


Nested sessions. Hypothetical:

  local computer with screen
  \
   \ ssh/mosh to remote A, run screen
    \
     \ ssh/mosh to remote B, run screen
If each uses the same prefix (the default is C-a for screen, C-b for tmux) then you have to send it multiple times to send a command to the screen sessions on either of the remote systems. If you give each a unique prefix then you can send the prefix once and it goes directly to the desired screen session.

Easier to give each system its own prefix that's constant regardless of depth, though, than trying to remember "Did I connect to A first or B first today?". Or, better in my experience, don't nest them. It's a pain however you choose to deal with the prefix problem.


Instead of keeping N terminals open for N projects, I usually keep only one open and put each project in a screen session, then wrap them all in a “meta” session.

I started using this pattern before I moved to macos, but now that I’m usually on a mac, it helps because I still haven’t gotten used to macos window / desktop management. Managing one terminal is easier than a half dozen.


I do that except with terminal emulator sessions. One window with few tabs per virtual desktop, as I rarely need to have more than 2-3 projects open at the time it works fine.

But... isn't tmux sessions exactly what you'd need for that? One session per project, then just connect to servers from within tmux windows

There is even switch-tree (default C-b w) that will show each session with every sub-window in it, and even preview window below that showing each terminal (refreshable via space)


The problem here is the reliance upon environment variables being set by parent processes. That's always felt weird to me.

I think tmux's choice is actually the sane one. You create the server once, then there's no more question about what environment variables are going to be established in the future.

When you create a new tmux window, you should know if there's already a server spawned.


> ...the reliance upon environment variables being set by parent processes. That's always felt weird to me.

I don't really agree. When I start a program in a shell, I expect it to inherit the environment of that shell. That's just how things have always worked, modulo some special cases (sudo, running a new instance of the shell in login mode, whatever).

I personally don't think that's weird, but even if I did, what I care most about software behavior is predictability. Software should do what is expected and common, and if it does not, it should have a very good reason, and should find a way to make that obvious to the user every time it does it.

This is just bad UX on tmux's part.

> When you create a new tmux window, you should know if there's already a server spawned.

What? Why? I use screen on and off, not super often. When I start a screen instance, I don't always know or care if I have another instance running somewhere. And yes, because screen follows what I'd consider a more predictable model here, I end up with the environment variables I expect.

I think whenever we attack a UX problem by saying "the user should know X", we've already lost. You can't assume that you know how the user is going to use your software, or what their state of mind will be when starting it. That's just silly.


I don't know about other people - but I spend greater than 99.9% of my time inside a tmux session. It is my windowing environment. I was reading the original post and just kept furrowing my brows wondering "Under what possible scenario could any of this possibly be a problem?"

It's kind of interesting reading through the threads here and seeing how people don't spend their time inside tmux all the time but instead "start an instance on demand" - which I've never done but I guess works for some people's workflow?

I'm genuinely crippled trying to use a terminal without tmux after having used it for so long - don't have the faintest clue how to copy/paste/search/organize windows without it.


I want to echo this sentiment as well. I never use bare terminal sessions. Not locally, and especially not remotely.

I think the tmux sentiment in question is held by people new to the tool or that don't use it as a normal part of their workflow or day-to-day.


Something like yakuake does tabbing, splitting, and is scriptable via dbus commands. There is no strong need to learn tmux key bindings to use locally.


I was a casual tmux user until I got stuck in a portable trailer in Dubai working for DEWA on their grid, and they had us using a janky remote terminal Remote Desktop setup that didn't have any form of mouse pass through to the linux terminals we were doing work on. So - copy/paste were not possible which made work a pain. I gave them a DVD (!) containing the various ncurses/libevent/tmux code - and voila - I finally had a working environment.

I spent 2+ months in that trailer for 6-8 hours/day - and tmux became so embedded in my finger DNA, I never looked back.

I routinely bounce between WSL, Linux, and MacOS and never have to remember any of the keyboard shortcuts for the terminal programs, or whether it's been installed, and my fingers never leave the keyboard - and I can almost always outperform someone trying to select/copy with a mouse/touch pad. My .tmux.conf is the only thing I pull along with me.

Also - just thinking about it - tmux is more than just a windowing environment - it also does project management. I have a workflow where every new project/issue/incident gets its own named window - and then I break up that window into a set of 4-8 panes based on systems (or sets of systems) I'll be working on. They all share the same bash_history. As I get hit with interrupts, I bounce between sessions and when I come back - my whole thought process/work history is back in that named window with panes. It's not unusual for me to have 45-50 open panes at a time - all perfectly organized by project/named window. With the resurrect plugin, and intelligent use of my bash config - I can (and do) pull everything (scroll back history, bash history, etc..) onto another system if needed (great if you need to recreate your work history and you no longer have access to the original terminal environment).

As I close off/complete projects, I terminate the window - but the bash history is kept clean in ~/.tmux/bash_history/window_name in case I ever need to start working on it again (recreating the window with the same name pulls back in the bash history)

Introspecting here a little, this honestly is probably more a function of me spending 40+ hours in a terminal environment than anything a rationale casual user would ever want to do.


If I'm running in a GUI terminal I can do most of those in there instead. I mostly end up using tmux if I need multiple tabs inside a ssh session.


Right but then when you ssh to your existing computer from another you won't have all your windows!


Sure, if this is a big part of your workflow then that makes sense. Personally, I end up running 1-2 workstation machines with GUIs that I sometimes remote out from, but ~never into (apart from sometimes retrieving files from the desktop when I'm away).


Ha! I didn't see you response before writing mine, but, yeah, I had the exact same reaction!


You are not using tmux for what it's designed to be used. It's not for running long-running processes, even though you might use it this way (you could also use eg. Photoshop to run long-running processes, after all, it has an embedded JavaScript interpreter with some extra functionality that might allow you to do that).

tmux serves the same purpose as DE, except w/o the whole windowing system etc. It's to allow you to switch between multiple applications which require terminal for interaction.

I spend close to 100% of my time at work inside tmux, and I never needed to answer a question "where do the process variables come from?" -- it's irrelevant in the same way how you don't ask where does Gnome get its environment variables from. You simply don't rely on environmental variables when running tmux / don't care about them.


> When I start a program in a shell, I expect it to inherit the environment of that shell.

That's exactly how tmux works. You start a server, it inherits the environment of the current shell. You create a new session in that server, it inherits the environment of the server.

I don't understand how forcing tmux to re-load the current local environment for each new shell is saner behavior. One natural consequence would be that new panes in existing sessions are also created with the new env vars, which is obviously undesirable.


>> When I start a program in a shell, I expect it to inherit the environment of that shell.

> That's exactly how tmux works. You start a server, it inherits the environment of the current shell. You create a new session in that server, it inherits the environment of the server.

Whether that makes sense depends on if your mental model has starting a server and connecting to a server to create a new shell as distinct actions, as opposed to a singular action of connecting to a conceptually always-present persistent environment and starting a shell there. Admittedly tmux’s interface is mostly organized along the former lines, but given I prefer `tmux new -A`, my own model seems to follow the latter.


I disagree. tmux default behaviour suits my workflow much better. It's complex enough problem that there is no perfect default so complaining this or that doesn't fit you when you can just change it so it does is pointless.


It would make sense if there were 2 commands, tmux-server for starting the server and tmux-client for starting the client. The client would then support options to connect to an existing server or spawn a new one.

I'm a big fan of abstracting away details of little importance. But if I risk using an old server with stale values in its environment, I prefer that to be made explicit and not abstracted away.


I agree that it is more sane and predictable.

I'm pretty happy with this behaviour and being able to tweak it if I need more.


How is that "predictable"? The standard behavior for more or less everything is that, by default, when you run a process, it will get its environment from the parent process. Getting its environment from a magical hidden server process that a casual user may not even know about is the opposite of "predictable".


it's not magical or hidden. every invocation of tmux is a call to a running tmux server. the only exception is when no server is running, in which case a new one is started.

i have tmux running all the time. started once when i connect to a server for the first time, it keeps running until the server is rebooted. i have tmux sessions that go back years.

the only time the environment is causing me trouble is when a new ssh connection is forwarding an ssh agent, which doesn't get transferred into the tmux session when i attach. but screen would not help here either. if you connect to an existing screen session it has the same problem. we really want a way to adjust the environment for specific variables on attach.


If you run an SSH client process to connect to an SSH server, the resulting SSH session will not inherit the environment from the parent process of the client by default. Although not the same, connecting to a tmux server is more similar to that than starting a regular child shell.


Environment variables get immutably set when you run the process, that screen would re-evaluate them when launching another window is bizarre. I'd expect the opposite case to be a problem, that when using screen you'd export environment variables by accident more often.


FWIW, as someone who uses screen, to me the opposite is "bizarre"? ;P I am at a shell, and I run "bash". This opens a new shell, but inherits both the environment and the working directory from my shell. Or maybe I run "ls": same thing. Now I run "screen bash" or "screen ls"... this should intuitively run the command as if I had just run the command but do so in a new "window". It would be absolutely ridiculous if "screen ls" didn't inherit the environment from the current shell.


Looks like zellij follows the same behavior as screen, if I'm testing right. I also prefer screen/zellij's choice here.


We had this happen at my company. I had set some new memory settings in a JAVA_OPTS environment variable due to heap issues. The DBA kept a tmux server running and would periodically restart our app when they needed to do work on those tables it interacted with during maintenance windows.

The heap issues kept occurring even though I triple checked the ENV variables. However, ps -ef showed the old values!

Once I figured out he was using tmux the issue was resolved by closing out all sessions and starting new ones.


I've gotten comfortable with the way tmux works, but the complaints raise a valid point. Its default behavior of prioritizing server environment over session environment is probably the wrong one. Maybe those who don't see this are conflating windows and sessions (I can clearly see this in the comments). Different sessions imply radically different projects, paradigms, contexts. Whereas different windows in a session imply different perspectives, views, within a shared paradigm.

Intuitively, it makes sense to be able to start a tmux session after setting up some global (i.e. session wide) environment variables, so that all new windows spawned in that session inherit them. Once you've specified the database or various urls, you don't want to have to source some environment file each time you spawn a window. The session should just already know all this.

Inheriting some super global variables (i.e. server wide, machine wide) by default (as opposed to explicitly setting a flag) implies that a shared environment across sessions is more useful than a shared environment across windows within the same session. It's a matter of opinion, taste, or maybe of UX data points, but I suspect that the latter would be favored if there ever was a survey.


In 10+ years, outside of perhaps experimenting with the feature for a few hours to see how it works - I've never created a second session in tmux. I routinely will have 20-25 windows and another 4-6 subpanes inside those windows though.

I'm wondering if sessions were more relevant before we all had 30+" monitors on our desk, and panes were less useful. Or perhaps some people have, as you noted, more well defined work/project paradigms that they can associate with a session.

With that said - in my day job, we have a really well engineered set of tooling that lets us manage our certificates, ssh keys, and orchestraor/security engine/service discovery tokens - but I'm managing and updating dozens of environments/configs - honestly the environment that I opened even a single pane (inside a window) might shift several times over 5-10 minutes into entirely different clusters - what that pane started with is mostly irrelevant - (and clearly the windows/session and "Tmux Server" environment that I started with is so irrelevant as to be meaningless).

About the only global original configurations that I care about and want to carry into my work are bound to my client (/etc/hosts, /etc/resolv.conf, interface, VPN, etc...)

The one thing that I've gotten out of this thread is that I probably should be more empathic to other people's workflow - not everyone has the same datacenter/cluster/server environments that I do - and instead of having tooling to manage their environment, they might just rely on what it was when they were launching a "new tmux session at that point in time" (a concept I had never considered until today).


The default behavior seems logical to me. At least I think it’s normal for general use cases.

I’m curious what was your case that triggered you to dig this up.


I agree with you. I suspect it is around understanding that tmux is a server, which you start and connect to.

Its my daily driver, but that means when I am in bare zsh, without tmux, it usually doesn't "work" for me. So, I can understand if someone is just spinning up tmux occasionally (to keep some long running program from stopping) that it can be a bit jarring. In some senses, the simpler 'screen' might actually be a better fit for that.

But yea, using tmux every day for years you become very thankful of how it operates, keeps variables isolated, you tend to work in one session per project (and it's great for not mixing them up).

But yea, it wouldn't be great if you are working away on something, then half way through just "start a session".

Tmux isn't going to do what the op is trying to do I suspect.

I'm a big tmux fan, it is awesome (in case that wasn't clear)


Interesting that you do one session per project - I've experimented occasionally with that, but I ended up in the one window per project, and then break up the work in to 4-8 panes (more or less). Every window gets a name (my new window shortcut requires it) so it's relatively straightforward (for me) to find the project context, particularly as the bash_history is named after the window, and shared between panes (so you can pull the entire work history for a project based on its name).


OP here. We have some make tasks that set up a local dev environment and rely on environment variables to control a few things. We ran into an issue where if someone started another tmux session and then ran the make task to start the dev environment the env vars wouldn't be set correctly causing some confusing behavior.


I wouldn't rely on env variables. I'd make a script that goes somewhat like

    script envname command
then just loads .env.envname before executing.

For k8s work I just put some relevant variables in PS1 so it is always visible "where I am", with prompt looking like this for say "dev" env:

    [08:15:57] ^ [~] 
    k8s:dev -> ᛯ 

As for tmux behaviour, it's honestly entirely understandable. tmux have no way of knowing the intent of the user; some people might want "clean" session with defaults of what server is running, other might want some env variables copied.

I don't have that problem because I just have session being created in my WM autostart, and I just use that one session 99.99% of the time. And creating new ones usually is from tmux, not from some random shell window elsewhere


Yeah that makes sense. To me it felt unintuitive that environment was global and only copied on server start, with a few exceptions, and not session start but that was likely just a failure in my mental model of how tmux worked.


I think it's about the stuff that needs to be shared. Like variables for X11 or ssh agent.

If you start server off your graphic session then any new tmux session will get those variables and your ssh agent or graphical app will "just work".

Reading from current one by default might fuck something up if you say have some automation that starts stuff in tmux

There isn't really good way to handle it by default that would make everyone happy, screen had similar "problems".

I just have

    tmux new-session -d -s main
in my .Xsessionrc so the main session gets both SSH_AGENT stuff (I use gnupg as agent, for smartcard support) and proper DISPLAY, then just use alias to use that main session


Could you encapsulate the config to a file within your build step and set the env vars from that? Like a “remember to source <envfile> before make dev” or better, if the env isn’t set in make properly (flag), have make source it.

Environment vars are great with defaults for configuring codebases. They are designed for runtime. Build time flags can read the current environment but if your build pipeline requires custom variables you need a “dictionary” of sensible defaults that will spin up a local environment so that onboarding is as easy as git clone && make dev.


I wonder if it's because of export. If one puts an env var into a command alone then it should be OK. For example, `MY_VAR=1 my-commmand.sh` should leave env vars unchanged for everything else.


Yes that should work. In our case we have a few different windows/panes that all want the same environment so it made sense to reach for export as a way to ensure the environment was set but then ran into this quirk of tmux


You can use the include syntax for Makefiles in order to include your environment variables.

Alternately, set those vars in your shell RC and it'll work too when the shell is spawned.

IME it's stabler to kick off automation or build processes from a clean slate anyways, clearing the environment and setting specific values as required from a file.


To me, this behaviour makes perfect sense and fits well with my intuition or mental model of how things work.

Thanks anyway for a good write up


I would have expected that sessions are completely independent from each other, and don't magically inherit some (but not others) environment variables from when the first session was created. (Especially considering the first session might not even exist anymore!)

That said, I can understand why it would work this way for simplicity, if all sessions are hosted inside the same process.

Luckily for me, I never use more than one session at a time, so this doesn't affect me.


It helps to understand that tmux is a server, that you connect to with sessions.

Your first spawn of tmux starts the tmux server, all your sessions will connect to this server

But if it is only one session you are using, w


> tmux show-environment

> [..]

> -WINDOWIDkj

Consequence of using Vim to edit blog posts? It should be, according to author's dotfiles :-P

Or maybe using tmux, because I also press kj to determine what pane I'm on sometimes.


hahah you caught me!


His solution of using `-L` to create a new named socket for each server does not seem cumbersome to me. I usually run `tmux attach-session` only once per day, so an additional argument would not be a major cognitive load. And I'd imagine most people use shell aliases for that sort of thing anyways (I probably should).


This is actually what I do every time. I thought it was standard practice.


yea i always do `tmux new -s dev` to start one and `tmux attach -t dev` to attach

correct me if im wrong but it seems like i can just do `tmux new -L dev` and `tmux attach -L dev` which is actually better than my old muscle memory. its a win-win for me

edit: actually jk it doesnt work.

meh who cares i always put my env vars in ~/.profile its weird how OP doesnt mention that at all


The -L option is for tmux so it needs to go before the command as `tmux -L dev new` and `tmux -L dev attach`.


oh. awesome! thank you kindly

edit: damn, now i have to write a custom script for `tmux list-sessions`

    #!/bin/bash
    for L in $(ls /private/tmp/tmux-501); do
        echo $L
        tmux -L $L list-sessions
    done
honestly at this point it isnt even worth it. i dont wanna have an extra script like this. ill just put my env vars in ~/.profile


I guess I would do something like `-L $$ `


`screen` for life, but at this point only for CLI remote sessions. Local terminal guis can p much do everything


I think the biggest problem I encounter when trying something else than tmux is copy-pasting without having to use the mouse. How does the "local terminal guis" you suggest as alternatives handle that?


Control-A-[ to enter copy mode, select text, control-A-] to paste


That's how to do it in screen, but not a local terminal GUI I know of.


If the terminal gui is Emacs then it handles copy-paste well ;)


But at that point you may as well use TRAMP[1] and let Emacs do the multiplexing for you. Yes, (e)shell works over TRAMP too. ;)

[1] https://www.gnu.org/software/tramp/


Not quite. I don't think my setup is very special, so, I describe it in more detail:

My company provides me with the laptop, VPN connection to the office network, which, in turn, connects to our (tiny) datacenter, where actual work happens (i.e. compilation, CI, testing, all happen there).

Sometimes I work from the office, other times from home.

The datacenter has several "jump" servers having distinct roles, there is a server that lets you connect to our OpenStack cluster, another has some resources to run a bunch of unrelated VMs in KVM, yet another one is the storage for all kinds of artifacts, s.a. Linux packages, Linux distro images, Docker images for development and testing, and then there's CI cluster.

So, my typical setup is like this: I have an ansi-term buffer per jump server. The jump servers are running my tmux session. So, every time I have to move my laptop to a different network (eg. going home from office), I reconnect to the jump servers and to the tmux session they were running so that I can pick up from where I left off before disconnecting from office VPN.

If TRAMP could have a persistent session, maybe, I'd not use tmux (I don't like that I have different commands for managing buffer appearance and clipboard). On the other hand, tmux is more universally used (at least in my company), so that sometimes I can simply ask a colleague to connect to my session, if they need to investigate some strange situation (only a handful of people are using Emacs, but almost everyone would be able to use tmux at where I work).


Might be worth looking into detached.el for persistent sessions? Tbh I haven’t set it up properly myself, but I did watch the talk from EmacsConf and I plan to look into it further.


Thanks for this! Unlike a stereotypical Emacs user, I haven't touched my configuration in a few years. Guess, I'll need to do some cleanup / research in the near future.


Have you looked at mosh?


Nope. Looks interesting though. I'll have to spend some time on that. Thanks!


I switched from screen to tmux because it was often impossible to detach a remotely attached screen (for example when your ssh connection dropped and you wanted to reattach to screen).


Would `screen -d -R` & al not work? From `man screen`:

       -d|-D [pid.tty.host]
            does not start screen, but detaches the elsewhere running screen session. It has the same effect as typing "C-a d" from screen's controlling terminal. -D is the equivalent to the power
            detach key.  If no session can be detached, this option is ignored. In combination with the -r/-R option more powerful effects can be achieved:
       
       -d -r   Reattach a session and if necessary detach it first.
       
       -d -R   Reattach a session and if necessary detach or even create it first.
       
       -d -RR  Reattach a session and if necessary detach or create it. Use the first session if more than one session is available.
       
       -D -r   Reattach a session. If necessary detach and logout remotely first.
       
       -D -R   Attach here and now. In detail this means: If a session is running, then reattach. If necessary detach and logout remotely first.  If it was not running create it and notify the user.
               This is the author's favorite.
       
       -D -RR  Attach here and now. Whatever that means, just do it.
       
            Note: It is always a good idea to check the status of your sessions by means of "screen -list".


Believe me I tried all combinations, lowercase and uppercase, it would just freeze, as if it was trying to get my session back, but it wouldn't do anything. It happened often, and I would lose my sessions, so I learnt to use tmux, and that's what I've been using for ten years.


Interesting, that's what I've been using since forever and a half in the exact scenario you describe.


Yeah... I kind of vaguely remember having an issue with this sort of thing 20 years ago, but I don't remember if I even knew about force detach at the time. I definitely haven't experienced a screen session I couldn't detach--and I use screen a LOT--in at least 10 years... probably 15.


    screen -d [optionally] pid
Will detach screen from within screen.

    screen -x [optionally] pid
Will reattached with simultaneous attachment.

    screen -r [optionally] pid
Will detach (if needed) and reattach the session.


May be I misunderstood the article but the tmux behavior I see is slightly different.

The env vars from the shell where most recent attach happens are inherited when creating a new pane or window. This is the case even when multiple terminals are attached to the same session.

I'm on version 3.3a for reference.


This seems similar to VSCode and it’s shell sessions. You need to restart VSCode to pick up new environment variables rather than just open a new shell. But at least you have a UI in your face to sort of remind you. With tmux server maybe it is less obvious that this will happen.


I don't think it's like that at all. It's pretty normal and expected that when you change env vars, existing shells won't pick them up.

In tmux's case, it starts new shells with "old" env vars, where "old" is "whatever was present when the first tmux session was started".


I mean a new shell within VSCode wont pick up env var changes made after VSCode was launched.

So it is roughly analogous:

VSCode ~ tmux server

VSCode shell ~ tmux pane

This is all expected and ergonomic I agree.


I don’t understand. I thought this was obvious? The other way is counter-intuitive.


At least to me, it seemed most intuitive to not have a global server environment and always copy the environment when starting a new session not just on server start and have the existing behavior when attaching to a session.


Somewhat related: I had no end of trouble trying to configure my locale on a raspberry pi. Tried everything I could find on the internet, still had inexplicable errors with environment variables not being set or being set differently than I had just set them.

It's because my ssh session was bringing variables from my laptop onto the pi:

https://stackoverflow.com/questions/2499794/how-to-fix-a-loc...


I think it's undocumented but you're supposed to be able to have update-environment set to '*' so it always uses the parent shell's environment variables when creating a new session.

I have a very quirky setup with tmux and rely on this feature, but it's broken IIRC and add important variables to update-environment manually.


Works for me, adding the following line to my .tmux.conf makes it inherit environment variables from the parent shell

    set-option -g update-environment "*"


My domain is ajm.codes and I can't tell you how jealous I am of the two character domain aj.codes

Anyways, I'm Not a tmux user but it seems like a nice default behavior to have env. variables persisted


This part at the end is something I use a lot to re-attach to a running session:

> to re-attach to the second session you’ll need to do tmux -L other attach -t second.

I have tmux running on a machine in my closet that I ssh to from a couple of different laptops. I name each session, and then always connect to the same session when I ssh into the closet machine.

  tmux a -d -t session-name
The -d makes the sessions resize to match the current scrren size which is useful for me because I use different screen resolutions on both laptops.


-d causes the other attached clients to become detached from the session. tmux, like screen, limits the size of the rendered window to the smallest presently connected. It happens that it forces a resize to match your current screen size, but that's not its primary purpose.


Ah, OK ... I couldn't get much from the man page, but I recalled that I needed that to get the resize - thank you for the explanation!


new-session -A will automatically create that session upon reboot.


If you want to retain complicated window setups without running multiple sessions concurrently I really like tmuxinator [1]. It lets you declare everything about the session in a config file, and restart the session based only on the file.

1. https://github.com/tmuxinator/tmuxinator


It's rather surprising how nuanced tmux can be considering its OpenBSD roots.


Does anyone remember Terminator? It was a VTE wrapped in Python IIRC and it allowed very flexible windowing of terminals.


This is an interesting bit of behavior but the article did not explain what real-world circumstances make this behavior meaningful.


It seems like the behavior would cause problems in the following workflow:

- create first session (launch server)

- detach

- set environmental variables

- create second session

But I don't understand why you would want to follow this workflow in practice.

When using tmux, all my work on that machine is done within tmux sessions, and I expect them to be sandboxed relative to each other. If I want to set an variable that's relevant to a session, I do it from within the session, not outside.


From a user perspective, it can look like indeterminate or unexpected behavior - the set of environment variables available within the tmux session depends on the state of the world at the time the tmux server was started, as opposed to when the session was started. The tmux server may start when the session starts, or it may have started much earlier - as a user, unless you're aware of this behavior and paying attention, you won't know.

Other posters are right that the "correct" workflow is to set all your environment variables explicitly within the session before launching whatever process you're running, but on an ad-hoc basis, I've often found myself logged into a server and thinking "this may take a long time, I should run this in a tmux session," and this kind of behavior would have (and probably has) bitten me in that case.


I've found for myself that it better start tmux/screen session on server up on login and don't spend time thinking on per case basis. So 95% on ssh sessions I use run tmux inside and usually the first command after ssh login is tmux attach. 5% cases are exception when no tmux/screen available or cannot copy my own tmux.conf


OP here. Apologies for not providing the real world example that triggered the behavior but here's some more background: We have some make tasks that set up a local dev environment and rely on environment variables to control a few things. We ran into an issue where if someone started another tmux session and then ran the make task to start the dev environment the env vars wouldn't be set correctly causing some confusing behavior.

Ultimately we decided to use a named tmux socket to ensure the environment variables were picked up correctly when set via the make task but you can also use `set-environment` as well if the ergonomics hit of having to use the named socket each time is too much. It's nice that tmux provides a few work arounds but I thought the original behavior was not intuitive.


Surely you'd run a script as part of your task to make sure it was all set correctly? This just seems like a bad setup.


If you thought you were reloading the dev environment database, and found out you just reloaded your production database, you would be surprised too. And you would probably wonder why after setting the dev variables, the tmux shell didn't have them.

It's one of those rare gotchas that will bite someone in the ass. And it will hurt. And when it does, you'll swear like a mother f'er.


Is this legal information?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: