I have the current git branch in an environment variable. The value of this variable can naturally change when I change the current directory. I want the value of this variable to be displayed in the current tmux pane status line (not altering the status lines of the other panes).
The following code works, but I don't like that it uses eval (in particular for performance reasons):
In .zshrc I make sure that tmux can access the variable, and that it is pane-specific by adding the pane_id value (without the %) in the name:
set_p10k_branch_in_tmux() {
tmux setenv -g TMUX_${TMUX_PANE#%}_VCS_BRANCH ${VCS_STATUS_LOCAL_BRANCH:-''}
}
precmd_functions+=set_p10k_branch_in_tmux
In tmux.conf I display the variable using this setting (I inserted a newline for readability)
set -g pane-border-format '#(TMUX_BRANCH_VAR=TMUX_#{s/%%//:pane_id}_VCS_BRANCH;
eval "TMUX_BRANCH=\$$TMUX_BRANCH_VAR"; echo "${TMUX_BRANCH}")'
I tried to use an indirect variable reference, e.g. echo ${(P)TMUX_BRANCH_VAR} but I couldn't for the life of me get it to work. I made a half-hearted attempt to use an associative array, but it seemed that associative arrays didn't work inside tmux.conf either.
Is there a way to get this to work without using eval? Or is there an altogether better solution to this problem?
Related
I'm trying to edit /.config/fish/config.fish and add script like this env now= date +%Y%m%d%H%M%S ;set path /Users/t/logs/script_{$now}.txt ;script {$path}. But it does not work.
How should I edit config.fish file in order to record terminal log including output ?
First, your attempt to incorporate a timestamp in the file name is wrong. It should be now=(date +%Y%m%d%H%M%S). Too, prefixing it with the env command means it won't be visible to the subsequent statements because the env causes the var to only be visible to whatever command is part of the env command. What you wrote is the equivalent of
env now=something
path=...
script $path
That first env will simply add now to the env vars then display the list of env vars.
Second, you should ensure this is only done for interactive shells:
if status is-interactive
now=(...)
set path /Users/...$now.txt
script $path
end
Third, you need to avoid infinite recursion. If you don't then the shell started by the script command will start another script'ed session. There are many ways to do this but the simplest is an env var:
if test -z "$SCRIPTED"
set -gx SCRIPTED nested
now=(...)
path=/Users/...$now.txt
script $path
end
Fourth, you may want to do exec script $path once you're sure this is working reliably. Otherwise when you exit the captured session you're returned to a non-capturing shell and you may not notice the transition. Alternatively, add something like echo WARNING: your session is no longer being captured after the script command to help make it really obvious.
I have something like that in a shell script
cd /some/folder1
savedCFLAGS=${CFLAGS-}
export CFLAGS="-fexceptions ${CFLAGS-}"
./configure --some-option -what-ever
make
export CFLAGS=${savedCFLAGS}
cd /some/folder2
./configure --some-option -what-ever
make
This works more or less correctly but has one serious flaw.If CFLAGS was unset previously, after the first block it will be set and empty.Sometimes, this is a problem, because some configure scripts use default values for variables only if they are actually unset - default value will not be used if the variable is simply empty.
Let me also state that I have such constructs multiple times in the script, with multiple different variables(this is a script used to build complete GCC-based toolchain).
What would be the easiest way to have the variable either restored to previous value (if it actually was set previously) or unset (if it was unset before my modifications)? I could set savedCFLAGS to some special token if it was unset, and then test whether savedCFLAGS has a value equal to that token.However, maybe there's something much simpler?
Just run your setenv+configure+make in a subshell using parentheses:
(export CFLAGS="-fexceptions ${CFLAGS-}";./configure --some-option -what-ever; make)
It inherits the environment in a copy, so when exiting the sub-shell you get the exact same "previous" state: no env. variables are ever changed in your script, and further configure commands work properly.
This question already has answers here:
What does the 'export' command do?
(3 answers)
Closed 7 years ago.
When I customize my environment, I add PATH=$PATH:$My-own-Path in file .bash_profile.
The tutorials tell me I should use this one: export PATH=$PATH:$My-own-Path
So, what is the difference?
To answer your exact specific question, in this particular case, there isn't any difference. Why?
Somewhere in the initialization process, the variable PATH has already been exported. A change in the variable's value which is already exported does not need another export; this is automatic. The processes fired hereafter will get the new value.
export makes the environment variable available to child processes
From man bash:
... The export and declare -x commands allow parameters and functions to be added to and deleted from the environment. If the value of a parameter in the environment is modified, the new value becomes part of the environment, replacing the old.
Also from man bash:
export [-fn] [name[=word]] ...
export -p
The supplied names are marked for automatic export to the environment of subsequently executed commands. If the -f option is given, the names refer to functions. If no names are given, or if the -p option is supplied, a list of names of all exported variables is printed. The -n option causes the export property to be removed from each name. If a variable name is followed by =word, the value of the variable is set to word. export returns an exit status of 0 unless an invalid option is encountered, one of the names is not a valid shell variable name, or -f is supplied with a name that is not a function.
Exported variables are available to other programs. Non-exported variables are not.
Example:
$ myVar=Foo # Create local
$ env | grep '^myVar='
$ export myVar # Export myVar to child process
$ env | grep '^myVar='
Foo
If you want to read more about this, check out export (GNU Bash manual).
Also, please note that non-exported variables will be available to subshells run with (...) and other similar notations:
$ thereVar=Bar
$ (echo $thereVar; echo $myVar; $myVar=testing; echo $myVar)
Bar
Foo
Testing
$echo $myVar
Foo
The subshell cannot affect variables in the parent shell.
For more information on subshells, please reference:
Command Grouping
Command Execution Environment
Every process has an area of memory called the environment block. In the environment block are environment variables. These look like ordinary variables, for example x=42.
In most shells (C shell is an exception) you move an ordinary variable into the environment block using export. That command can also create an environment variable without going through an intermediate stage. If the variable is already in the environment block then export will have no effect.
So why? When a new process is created, the default action is to copy various "core information" from parent to child. These include the current directory, the umask, the file descriptor table, the uid and gid, and the environment block.
Note that the child only gets a copy of the parent's environment block. The variable is not shared and cannot be passed back to the parent (except by using some other inter-process communication mechanism).
You can override this default behaviour using the env program, but this is rarely required.
So, if we set an environment variable in a shell script using export then all our child processes we create, when we call other programs, will get a copy of them. Some variable names are well-known and have a special meaning, and the PATH environment variable is probably the most important of those.
The PATH environment variable is used to find programs on UNIX/Linux. Directories in PATH are searched in left-right order each time we need to load a program. Bash also caches executable paths in a hash (KornShell calls them "tracked aliases").
Oh... Probably title is not really easy to interpret. So let's describe it a little bit:
In .bashrc file I set PS1 to get custom prompt. In this prompt I need to have some additional info, which I get from other specific function. This function takes some time to exec so it is not cool to wait 1 sec after push enter in console. But I have idea to cached returned value from this specific function.
I need to check cache flag in every prompt print so I cant use variable, I must use function in printing prompt, because sourceing .bashrc is only one times, but if I pass function to PS1 it will be execed every time.
prompt_fun(){
export CACHE_YES=1
export PROMPT_CACHE="Something"
echo "$PROMPT_CACHE"
#in real case here will be checking if cache is turned on.
#If yes, we use cached value from exported variable in first time.
#If no, we exec specific function and export values to env variables.
}
PS1="$(prompt_fun): "`
Of course, variable CACHE_YES and PROMPT_CACHE are not set in console, so I am unable to control caching be changing CACHE_YES. I know when cache should change so I can type in console to change CACHE_YES=0 but my script don't rechange it to CACHE_YES=1 after cache new values.
How to make that export in prompt_fun have global effect?
The short answer is, you can't. Since prompt_fun is called in a command substitution, any changes made to variables in that subshell disappear when the subshell exits.
Instead, you'll want to set the value of PS1 inside prompt_fun, then call prompt_fun from the value of PROMPT_COMMAND, as the value of that parameter is executed in the current shell context prior to each prompt being displayed.
prompt_fun () {
if [[ -z $CACHE ]]; then
# Set value of $CACHE
fi
PS1=something
PS1+=something_else
PS1+=$CACHE
PS1+=final_value
}
PROMPT_COMMAND='prompt_fun' # Yes, single quotes
I have a bash script as follows:
rvm use 1.8.7
rvm list
The first line is a function loaded within my .bashrc file that defines some enviroment variables. When executing the second line, those variables have been set to their previous values (the set values have been lost). What am I missing here?
Running on a ubuntu box.
A subshell is being created and the variables are set within it. When the subshell exits, the changes are lost. This often happens when a while loop is in a pipe. Without seeing the function it's impossible to be more specific than that.
when you define environment variables that you want to make available to all subshells you need to prefix it with export like so:
export myvar="some value"
I would check that rvm is doing this properly