How to permanently set env across every session in fish shell? - linux

I install the cargo building environment.
I use cargo install exa to install exa (an alternatives of command ls).
Executable file is put in $HOME/.cargo/bin.
I use fish shell set -gx PATH $PATH $HOME/.cargo/bin, and then I can use command exa on current session.
But when I open a new session, I cannot execute exa unless set -gx ... again.
I look in the options gx:
--global -g (Make variable scope global)
--export -x (Export variable to subprocess)
Does not global mean every session? Could someone help me pls?

Doesnot global means every session?
It doesn't. It's "global" as opposed to "local". From the fish documentation:
Global variables are specific to the current fish session, and will never be erased unless explicitly requested by using set -e.
In general, what you want is to just put the set -gx into ~/.config/fish/config.fish. That's fish's configuration file.
Fish also has "universal" variables, which are stored persistently, but they interact awkwardly with exporting so I wouldn't recommend it.
For $PATH specifically, fish offers the fish_user_paths variable that it adds automatically, so you can run
set -U fish_user_paths $fish_user_paths $HOME/.cargo/bin
once, interactively, and fish will take care of it. This is a universal variable, but fish takes care to add it to $PATH when necessary (for each component it checks if it's already there and such). Do not put this into config.fish, or it will add one $HOME/.cargo/bin every time you start a fish, and so it would balloon the variable.
To recap:
For global variables, put the set statement into config.fish
For universal variables, execute it manually
For $PATH, use $fish_user_paths for your customizations

Related

Can fish, zsh and bash import the same configuration file?

I've recently been trying to switch from bash to zsh, or fish.
I have some alisa and PATH settings, but I don't want to manually copy them to zshrc or config.fish.
I tried writing them in a single file and using source ~/.myshrc to use them.
The alisa statement can be sourced normally. But when sourcing PATH in fish shell I got an error:
In fish, please use {$JAVA_HOME}. export
CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
I know that fish and bash syntax are incompatible.
So is there a general syntax that allows me to modify the PATH in myshrc and then all three shells can use it?
myshrc file like this:
# alias
alias apts="apt search"
alias sf="aptitude search -F '%c %p %d %D %I'"
alias apti="sudo aptitude install"
alias aptup="sudo aptitude update"
alias aptgr="sudo aptitude upgrade"
alias aptpu="sudo aptitude purge"
# transset xterm
transset -t -a 0.95 >> /dev/null 2>&1
# set npm path
export PATH=~/.npm-global/bin:$PATH
# set java path
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export JRE_HOME=${java_home}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
# set android path
export ANDROID_HOME="/home/moly/Launcher/AndroidSDK/"
export PATH="${PATH}:${ANDROID_HOME}tools/:${ANDROID_HOME}platform-tools/"
Short answer:
If you embrace the "fish way" of doing things, you can get your startup config down to just one line ...
Explanation:
First off, just to pass along some random knowledge (that I originally learned here in a related answer on Stack Overflow), code that is written in such a way that it runs the same way in two different languages is known as a polyglot. It's typically considered a "puzzle" of sorts, rather than a practical implementation. It's really not advised as a solution to your question.
Next up, my general recommendation is to embrace the fish way of doing things as much as possible. Sure, there are times you'll need to drop back to POSIX for compatibility reasons, but fish syntax is (IMHO) much cleaner.
I especially like that, under fish, my config files are almost empty. It's just not necessary under fish to have many of the items that you have in your bash startup.
Let's break down the four types of items you have in your startup config:
Aliases
$PATH changes
Other exported variables
Other Command(s)
Aliases
I recommend against putting aliases in your fish startup files. It's just not necessary. Instead, define the alias once at the commandline and use the -s (save) option. In your case:
alias -s apts="apt search"
alias -s sf="aptitude search -F '%c %p %d %D %I'"
alias -s apti="sudo aptitude install"
alias -s aptup="sudo aptitude update"
alias -s aptgr="sudo aptitude upgrade"
alias -s aptpu="sudo aptitude purge"
Your aliases will be "permanently" defined at that point in all fish instances, with the advantage that they are "lazy loaded" (only loaded into memory when you run them the first time) rather than being loaded at all times.
$PATH modifications
Likewise, fish provides a handy helper with which you can add to your path once and have it take effect in all instances (both currently running and future).
fish_add_path "~/.npm-global/bin" "/usr/lib/jvm/java-17-openjdk-amd64/bin" "~/Launcher/AndroidSDK/tools" "~/Launcher/AndroidSDK/platform-tools"
This prepends those paths to the built-in fish universal variable$fish_user_paths which is automatically prepended to the system path. Note that, in your bash rc, you have appended the Android SDK paths, but that's probably not necessary. Typically, you will want to prepend user paths ahead of the system path.
Other exported variables
This part is a little contentious, because fish universal variables can have unintended side-effects when exported to other processes.
On one hand, one of the fish maintainers (#faho) mentions in this answer that:
In general, what you want is to just put the set -gx into ~/.config/fish/config.fish. That's fish's configuration file.
Fish also has "universal" variables, which are stored persistently, but they interact awkwardly with exporting so I wouldn't recommend it.
I've had others (see comments on this answer) who have worked extensively with fish advise against it as well.
On the other hand, 196 upvotes on this answer seem to indicate that folks like universals for this purpose. That's not to say that the majority is correct -- I've seen some really bad answers with a lot of upvotes.
However, I personally like using them to simplify my config files.
If you so choose, you can:
set -Ux JAVA_HOME "/usr/lib/jvm/java-17-openjdk-amd64"
set -Ux JRE_HOME "$JAVA_HOME/jre"
set -Ux --path CLASSPATH ".:$JAVA_HOME/lib:$JRE_HOME/lib"
set -Ux ANDROID_HOME "/home/moly/Launcher/AndroidSDK/"
Again, as these are universal variables, they only need to be set once on the commandline. You can then remove those statements from your fish startup.
Understanding universal/global variable shadowing:
Primarily, if a global variable is set (for instance, by the parent bash process from which you launch fish), then it will override a universal variable of the same name.
For instance (pathologic example, but can easily occur in the real world, especially if you aren't aware of the potential):
# Start in Fish
-> set -Ux JAVA_HOME "/usr/lib/jvm/java-17-openjdk-amd64"
-> set --show JAVA_HOME
$JAVA_HOME: set in universal scope, exported, with 1 elements
$JAVA_HOME[1]: |/usr/lib/jvm/java-17-openjdk-amd64|
-> bash
-> export JAVA_HOME="~/.local/share/jvm/java-17-openjdk-amd64"
-> fish
-> set --show JAVA_HOME
$JAVA_HOME: set in global scope, exported, with 1 elements
$JAVA_HOME[1]: |~/.local/lib/jvm/java-17-openjdk-amd64|
$JAVA_HOME: set in universal scope, exported, with 1 elements
$JAVA_HOME[1]: |/usr/lib/jvm/java-17-openjdk-amd64|
In that particular fish session, the Universal variable will be shadowed by the global one that was exported in bash.
See this Github issue of many that demonstrate the real world potential for problems.
Again, with that in mind, I personally believe the benefits of exported universal variables outweigh the risks, but I wanted to be sure to present both viewpoints.
Other commands
If you've followed along so far (and haven't fallen asleep -- I known I over-explain ...), then you'll realize that there's (potentially) only the one command that must remain in your fish startup:
transset -t -a 0.95 >> /dev/null 2>&1
Even then, I have a suggestion. Fish automatically sources any .fish file in ~/.config/fish/conf.d. I like to keep my config "modularized", so that I can tell at-a-glance what is being loaded at startup.
I would just create:
~/.config/fish/conf.d/xterm.fish:
transset -t -a 0.95 >> /dev/null 2>&1
At that point, you are running like I do -- no fish.config at all! (Well, other than the fact that the newer fish versions irritatingly, automatically create a completely unnecessary empty one if it doesn't exist ...)
One hacky way to use your existing configuration while trying to transition to a new shell like fish is simply to end your ~/.bashrc with fish, like so:
# alias
alias apts="apt search"
alias sf="aptitude search -F '%c %p %d %D %I'"
alias apti="sudo aptitude install"
alias aptup="sudo aptitude update"
alias aptgr="sudo aptitude upgrade"
alias aptpu="sudo aptitude purge"
# transset xterm
transset -t -a 0.95 >> /dev/null 2>&1
# set npm path
export PATH=~/.npm-global/bin:$PATH
# set java path
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export JRE_HOME=${java_home}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
# set android path
export ANDROID_HOME="/home/moly/Launcher/AndroidSDK/"
export PATH="${PATH}:${ANDROID_HOME}tools/:${ANDROID_HOME}platform-tools/"
# start fish
exec fish
I don't think this is a very good solution, but this is the only one I know of to make fish inherit your bash environment without rewriting/translating your bashrc. While this is probably bad practice and could cause other sorts of issues, on the short term this could be what you need if you just want to try out fish in known territory with your aliases and PATH without spending time writing a configuration file perhaps for nothing.
I have no experience with zsh and don't know if it can equally inherit the bash environment like that, but wouldn't be surprised if it can.

Can't find who sets http_proxy environment variable on Ubuntu

I'm on Ubuntu 16.10,
When running in terminal:
env | grep proxy
I get:
https_proxy=https://127.0.0.1:8888/
http_proxy=http://127.0.0.1:8888/
I can't find who sets these environment variables.
I've tried all the answers here and could not find anything.
Tried different shells / terminals. Variables are always there.
Any idea what else can it be?
No luck in checking all the usual suspects? Then it's time to use the big gun:
find /etc $HOME /usr/local -type f | xargs grep -E 'https?_proxy'
Run this as root. Add directories to your liking.
An environment variable in your current shell can only be set in the parent process, or in a file sourced by your shell. I would start by turning on the shell trace in the respective rc-files which are sourced when you log in, in your home directory. This is also the place where I would verify whether the environment variables is already set at this point (which would mean that it was set by the global initialization process, for instance in the rc files which reside in /etc). Now log in and check the output.
If the environment variable is already set initially, you can't do much except bugging your admin that he should remove it (which probably won't work). If it is not set initially, you need to look through the output of the shell trace, until you either find the point, where the variable is set, or where you see that some malicious script turns off the trace.
Since you didn't give any information, which shell you are using, I can't go into deeper detail.
In my case those env variables were set by Fiddler web debugger and I was able to remove them manually by editing ~/.bashrc file. There are 2 lines with export http(s)_proxy... located at the end of this file. Hope that it helps!

Android Studio - cmake - access environement variable?

This question is specific to using cmake as part of Android Studio build process.
I'm using Android Studio 2.2 preview 7 on linux (ubuntu)
Inside the CMakeLists.txt I am able to access the Android NDK path using: ${ANDROID_NDK}
But how can I access:
Any environment variable ?
If not possible, at least the Android SDK path ?
I already tried to used $ENV{name_of_the_environment_variable_here} but it's always empty, even if the environment variable exist. I guess that when gradle invoke cmake it "hide" the env var somehow.
I don't think you can use $ENV, it's just an example of a variable because they're environment variables. However, you should be able to type env and hit enter for a list of the variables you currently have set. Then, the ones you see in the list, you can invoke by typing $VARIABLE_NAME, using a command before them to get them to do something. E.g. echo $VARIABLE will echo your variable to stdout.
I'm not sure how $ANDROID_SDK was set, if it was part of an install process, etc. but generally you would set user environment variables in .profile, .bash_profile or .bashrc configuration files. These files are read by the shell in that order. System-wide variables are set in /etc/environment, /etc/profile, and /etc/bash.bashrc, but you probably don't want to mess with those (most distros encourage making ancillary additions in /etc/profile.local, but that's a story for another answer).
It doesn't particularly matter which one of these files you use, unless what you're trying to do interacts with the order in which they are loaded. Generally, I look for where the variables have been set by either the OS or other stuff I've added and put them near those. You can find where environment variables are set by typing:
% for i in .profile .bash_profile .bashrc; do grep -H PATH $HOME/$i; done
(% is the prompt, don't type %)
.. and this will loop through the 3 files and show you if a user $PATH is set in any of them.
Bash uses the export ENV command as opposed to set ENV, which is from the original sh, which AFAIK is only default on FreeBSD and derivatives like pfSense anymore. Almost all other OS use Bash by default, except MacOS which recently moved to zsh and also uses export, and OpenBSD which uses ksh (nobody uses OpenBSD).
If you want to verify which shell you are using, type echo $SHELL, or echo $0 and hit enter, and it should let you know.
You can add the environment variable ephemerally by typing this command in your bash terminal and pressing enter:
% export ANDROID_SDK_ROOT=/home/username/AndroidSDK
To be clear, this is an example path, so it'd be best to use the actual path in which your android SDK files reside. However, this example was a default install location Android Studio tried to use when I installed it recently, so if you're not sure where they are, it's probably a good place to check.
To have a more permanent setting of your environment variable, open a text editor and add the line above to one of the configuration files I mentioned in the first paragraph (they'll be in your $HOME folder). Or, you can run this from the prompt and it'll add it to your file automatically:
% echo 'export ANDROID_SDK_ROOT=/home/username/AndroidSDK' >> $HOME/.bashrc
Take care to use two angle brackets and not one, as one angle bracket will overwrite the entire file with the single line.
How can I access Any environment variable ?
If you're not sure which folder is $HOME, try typing cd $HOME and hitting enter - that'll take you there. That's how you access environment variables - use a command with the invocation of the variable and it should act as if you had typed out the entire thing.
To access environment variables, type echo $NAME_OF_VARIABLE and it should echo it to the screen. If you want to search your three config files I mentioned in the beginning for where an environment variable is set, you can use grep as I did earlier, just changing the search string for whatever you're looking for. E.g. (while in $HOME):
% grep SDK_ROOT .bashrc .profile .bash_profile
Or you can type env to list all the currently set variables and filter them by piping the output to the grep command:
% env | grep SDK
If you want to just list all of the set variables and root around the entire thing, just type env instead of piping it to grep (grep's a filter).
Lastly, I'll give you an example of my $ANDROID_SDK_ROOT $ANDROID_SDK and $SDK_ROOT variables in my .bashrc - I noticed while installing these tools, they use all three (isn't that fun?):
% grep ANDROID .bashrc
export ANDROID_SDK=$HOME/development/Android/SDK
export ANDROID_SDK_ROOT=$HOME/development/Android/SDK
export PATH=$PATH:$ANDROID_SDK:$JAVA_HOME:$ANDROID_SDK/cmdline-tools/latest/bin:$ANDROID_SDK/build-tools/32.0.0:$ANDROID_SDK/emulator:$ANDROID_SDK/emulator/bin64:$ANDROID_SDK/tools:$ANDROID_SDK/tools/bin:$ANDROID_SDK/extras:$ANDROID_SDK/platform-tools:$HOME/development/AndroidStudio/bin
export ANDROID_STUDIO=$HOME/development/AndroidStudio
% grep SDK_ROOT .bashrc
export SDK_ROOT=$HOME/development/Android/SDK
export ANDROID_SDK_ROOT=$HOME/development/Android/SDK
Hope that answers some questions, sorry it took so long to give you a response.

How to remove permanently a path from the fish $PATH?

This question has already been asked, and answered here: https://superuser.com/a/940041/293429
However, the provided solution: executing set -e PATH[<index-of-the-path-to-be-removed] only applies to the running instance and is not valid universally.
After executing that command, if one executes echo $PATH the previously removed paths will occur again.
One way to completely reset the path is to execute: set -U fish_user_paths, but it is unclear to me that what it does.
The real trick would be to find out how to remove a path which has been manually added and make it available globally -- not only for the current instance?
There's two ways to do this, and which one is valid depends on how the path got into $PATH.
It is possible to add directories to $PATH via e.g. set PATH $PATH /some/dir. At least by default, PATH is a global variable, which means it is per-session. That means to change something from $PATH, either remove it from where it is added (which is likely outside of fish since it inherits it), or put the set -e call in your ~/.config/fish/config.fish so it will be executed on every start.
There is also $fish_user_paths, which is a universal variable (meaning it carries the same value across fish sessions and is synchronized across them). On startup and whenever fish_user_paths is modified, fish adds it to $PATH. If the offending directory is added here, execute set -e fish_user_paths[index] once (e.g. in an interactive session).
set -e fish_user_paths would remove the entire variable (while set -U fish_user_paths would clear it) which would also work but would also remove all other paths

How to set environment variable for everyone under my linux system?

Can I have certain settings that are universal for all my users?
As well as /etc/profile which others have mentioned, some Linux systems now use a directory /etc/profile.d/; any .sh files in there will be sourced by /etc/profile. It's slightly neater to keep your custom environment stuff in these files than to just edit /etc/profile.
If your LinuxOS has this file:
/etc/environment
You can use it to permanently set environmental variables for all users.
Extracted from: http://www.sysadmit.com/2016/04/linux-variables-de-entorno-permanentes.html
man 8 pam_env
man 5 pam_env.conf
If all login services use PAM, and all login services have session required pam_env.so in their respective /etc/pam.d/* configuration files, then all login sessions will have some environment variables set as specified in pam_env's configuration file.
On most modern Linux distributions, this is all there by default -- just add your desired global environment variables to /etc/security/pam_env.conf.
This works regardless of the user's shell, and works for graphical logins too (if xdm/kdm/gdm/entrance/… is set up like this).
Amazingly, Unix and Linux do not actually have a place to set global environment variables. The best you can do is arrange for any specific shell to have a site-specific initialization.
If you put it in /etc/profile, that will take care of things for most posix-compatible shell users. This is probably "good enough" for non-critical purposes.
But anyone with a csh or tcsh shell won't see it, and I don't believe csh has a global initialization file.
Some interesting excerpts from the bash manpage:
When bash is invoked as an interactive
login shell, or as a non-interactive
shell with the --login option, it
first reads and executes commands from
the file /etc/profile, if that file
exists. After reading that file, it
looks for ~/.bash_profile,
~/.bash_login, and ~/.profile, in that
order, and reads and executes commands
from the first one that exists and is
readable. The --noprofile option may
be used when the shell is started to
inhibit this behavior.
...
When an
interactive shell that is not a login
shell is started, bash reads and
executes commands from
/etc/bash.bashrc and ~/.bashrc, if
these files exist. This may be
inhibited by using the --norc option.
The --rcfile file option will force
bash to read and execute commands from
file instead of /etc/bash.bashrc and
~/.bashrc.
So have a look at /etc/profile or /etc/bash.bashrc, these files are the right places for global settings. Put something like this in them to set up an environement variable:
export MY_VAR=xxx
Every process running under the Linux kernel receives its own, unique environment that it inherits from its parent. In this case, the parent will be either a shell itself (spawning a sub shell), or the 'login' program (on a typical system).
As each process' environment is protected, there is no way to 'inject' an environmental variable to every running process, so even if you modify the default shell .rc / profile, it won't go into effect until each process exits and reloads its start up settings.
Look in /etc/ to modify the default start up variables for any particular shell. Just realize that users can (and often do) change them in their individual settings.
Unix is designed to obey the user, within limits.
NB: Bash is not the only shell on your system. Pay careful attention to what the /bin/sh symbolic link actually points to. On many systems, this could actually be dash which is (by default, with no special invocation) POSIXLY correct. Therefore, you should take care to modify both defaults, or scripts that start with /bin/sh will not inherit your global defaults. Similarly, take care to avoid syntax that only bash understands when editing both, aka avoiding bashisms.
Using PAM is execellent.
# modify the display PAM
$ cat /etc/security/pam_env.conf
# BEFORE: $ export DISPLAY=:0.0 && python /var/tmp/myproject/click.py &
# AFTER : $ python $abc/click.py &
DISPLAY DEFAULT=${REMOTEHOST}:0.0 OVERRIDE=${DISPLAY}
abc DEFAULT=/var/tmp/myproject

Resources