Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set and use variable in tmux.conf depending on whether an environment variable is set

Tags:

tmux

(Disclaimer: I am fully aware that there are solutions to the problem I describe below that involve writing and calling shell scripts that interact with a running tmux server, or set the necessary environment variables before starting the tmux server. I am specifically posting this questions to see if it possible to solve this problem without the use of such scripts.)

Problem Summary

In my .tmux.conf file, I am trying to set a local variable VALUE to different values depending on whether an environment variable FOO has been set before invoking tmux or not. I then want to use VALUE in other tmux commands. Unfortunately, I either cannot set VALUE correctly or access it after it has been set.

Previous Attempts

According to what I have found in the manpage and in other Q&A posts that contain sample tmux code, there are several ways to implement the above.

Attempt 1

I first tried using the if-shell command. I attempted using this command both with and without the -b flag; the result was the same in either case.

I have seen from examples that I can assign variables with the syntax VALUE=bar. Given that, here is a minimal example of my configuration:

if-shell '[ -z "$FOO" ]' \
    'VALUE=bar' \
    'VALUE=baz'

set-environment -g RESULT $VALUE

Terminal session:

$ echo $FOO

$ tmux
[detached (from session 0)]
$ tmux showenv -g VALUE
VALUE=bar
$ tmux showenv -g RESULT
RESULT=
$ killall tmux
$ export FOO=foo
$ echo $FOO
foo
$ tmux
[detached (from session 0)]
$ tmux showenv -g VALUE
VALUE=baz
$ tmux showenv -g RESULT
RESULT=

So while VALUE seems to have been set correctly, RESULT does not seem to able to access VALUE.

Attempt 2

The manpage also mentions that commands can be conditionally executed using %if statements. Using this format, I tried the following configuration:

%if #{#(if [ -z "$FOO" ]; then echo 1; else echo 0)}
VALUE=bar
%else
VALUE=baz
%endif

set-environment -g RESULT $VALUE

For the expression in the %if statement, I tried several variations, such as

  • #{#([ -z "$FOO" ])} (I believe this shouldn't work since this command does not produce any output, but it was worth a try.)
  • #{==:#(if [-z "$FOO" ]; then echo 1; else echo 0),1} (Just in case an explicit comparison would work)

Even with these variations, regardless of whether FOO was set or not, I got the following:

$ tmux
[detached (from session 0)]
$ tmux showenv -g VALUE
VALUE=baz
$ tmux showenv -g RESULT
RESULT=baz

Thus while VALUE was accessible, it was always baz.

Unfortunately, I have been able to find no useful examples regarding the formats used in conditional statements. The manpage describes how to access tmux variables and some formatting hints; however, regarding accessing environment variables, all I could find was a way to use shell commands:

In addition, the first line of a shell command's output may be inserted using #(). For example, #(uptime) will insert the system's uptime. When constructing formats, tmux does not wait for #() commands to finish; instead, the previous result from running the same command is used, or a placeholder if the command has not been run before.

I am unsure of whether this means I need to call commands in #() twice to avoid using a placeholder value, which may be a possible error on my part.

I was also unable to find a way to print the result of #{} commands easily to debug this part of the statement.

Summary of Questions

While I would appreciate any pointers to information that may help me solve this problem, the most pressing questions for me are:

  • Why is VALUE being set correctly, yet not accessible to RESULT in Attempt 1?
  • How should my conditional be written in Attempt 2 to ensure that VALUE is set correctly?
like image 685
Stipe Matic Avatar asked Apr 24 '19 21:04

Stipe Matic


People also ask

Does tmux inherit environment variables?

It gives the option to set tmux as the default shell, and spawn it directly. This way tmux does not inherit environment variables from shells.


1 Answers

The way tmux runs the config is by parsing the config file into a set of commands, and then executing them (there is a command queue, so the config file is parsed and appended to the queue and then executed from the queue). So there are distinct parse and execution steps.

The problem you are running into with attempt 1, is that the if-shell is run at execution time, but the $VALUE expansion happens at parse time. VALUE is not set when the set-environment command is parsed.

In attempt 2, #() is not processed inside %if so that won't work. However, you can use the variable directly in formats (if it is set). %if happens at parse time.

So you need to make sure assignment and expansion happen in the right order. You have a couple of choices.

You could make tmux expand the variable at command execution time rather than parse time. You can do this by wrapping the setenv inside run-shell, so something like:

   if-shell '[ -z "$FOO" ]' \
       'VALUE=bar' \
       'VALUE=baz'
   run 'tmux setenv -g RESULT $VALUE'

Or you could do the assignment at parse time like you tried in attempt 2, but you can't use #() - you need to use a format instead:

   %if #{==:#{FOO},}
   VALUE=bar
   %else
   VALUE=baz
   %endif
   setenv -g RESULT $VALUE

(Note that X=Y in the config file is equivalent to setenv -g X=Y except it happens when parsing rather than executing - both set the global environment. So you could get rid of VALUE and do either RESULT=bar or setenv -g RESULT bar inside the %if.)

like image 126
Nicholas Marriott Avatar answered Oct 12 '22 04:10

Nicholas Marriott