Aliasing two different versions of the same program in linux? - linux

I have an old version of a program sitting on my machine. This program recently had a version upgrade. The way I used to run my old program was by typing "runProgram". The path to the runscript of my program was specified in my PATH variable as
PATH = ....:/path/to/my/old/programs/bin
I want to run the new version of this same program alongside my old program and the way I was thinking of doing it was by modifying my PATH variable as follows:
PATH = ....:/path/to/my/old/programs/bin:/path/to/my/new/programs/bin
What I want to achieve is some way to alias these two paths so that when I type 'runVersion1', the previous version is executed and when I type 'runVersion2', the new version is executed?
Is there a way to achieve that?
Thanks

If the program itself runs other programs from the bin directory, then when you run a version 1 program, you want to ensure that the version 1 directory is on the PATH ahead of the version 2 directory, and vice versa when you run a version 2 program. That is something I deal with all the time, and I deal with it by ensuring that the PATH is set appropriately.
In my $HOME/bin, I would place two scripts:
RunVersion1
export PATH=/path/to/my/old/programs/bin:$PATH
# Set other environment variables as needed
exec runProgram "$#"
RunVersion2
export PATH=/path/to/my/new/programs/bin:$PATH
# Set other environment variables as needed
exec runProgram "$#"
This technique of placing shell scripts on my PATH ahead of other programs allows me to pick which programs I run.
Semi-Generic Version
Often, I'll use a single program to set the environment and then link it to the various program names that I want to handle. It then looks at $0 and runs that:
export PATH=/path/to/my/new/programs/bin:$PATH
# Set other environment variables as needed
exec $(basename $0 2) "$#"
If this script is linked to RunProgram2, the basename command lops off the 2 from the end of RunProgram2 and then executes RunProgram from the more recent directory.
I've used this general technique for accessing 32-bit and 64-bit versions of the software on a single machine, too. The programs I deal with tend to have more complex environments than just a setting of $PATH, so the scripts are bigger.
One of the main advantages of scripts in $HOME/bin over aliases and the like is that it doesn't much matter which shell I'm stuck with using; it works the same way. Plus I don't have so many places to look to find where the alias is defined (because it isn't defined).

I would put two alias definitions in your ~/.bashrc (depending what shell you are using).
alias runVersion1='/path/to/my/old/programs/bin/program'
alias runVersion2='/path/to/my/new/programs/bin/program'
After editing that file you need to relogin or simply execute
. ~/.bashrc

The way you suggest with $PATH won't do what you want. One way that might:
Given that usually, /usr/local/bin is in $PATH, and that that is the standard location for "local binaries", you do the following:
sudo ln -s /path/to/my/old/programs/bin/myprogram /usr/local/bin/runVersion1
sudo ln -s /path/to/my/new/programs/bin/myprogram /usr/local/bin/runVersion2
Alternatively, if you don't want it to be system-wide (i.e. instead, just for your user), you could:
ln -s /path/to/my/old/programs/bin/myprogram $HOME/bin/runVersion1
ln -s /path/to/my/new/programs/bin/myprogram $HOME/bin/runVersion2
(assuming $HOME/bin is in your $PATH)
Now this won't necessarily fix your problem - could use a little more information in the question, BUT it should help you get further with what you're trying to do.

Related

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.

Getting bash script to update parent shell's Environment

I am attempting to write a bash command line tool that is usable immediately after installation, i.e. in the same shell as its installation script was called. Lets say install-script.sh (designed for Ubuntu) looks like:
# Get the script's absolute path:
pushd `dirname $0` > /dev/null
SCRIPTPATH=`pwd`
popd > /dev/null
# Add lines to bash.bashrc to export the environment variable:
echo "SCRIPT_HOME=${SCRIPTPATH}" >> /etc/bash.bashrc
echo "export SCRIPT_HOME" >> /etc/bash.bashrc
# Create a new command:
cp ${SCRIPTPATH}/newcomm /usr/bin
chmod a+x /usr/bin/newcomm
The idea is that the new command newcomm uses the SCRIPT_HOME environment variable to reference the main script - which is also in SCRIPTPATH:
exec "${SCRIPT_HOME}/main-script.sh"
Now, the updated bash.bashrc hasn't been loaded into the parent shell yet. Worse, I cannot source it from within the script - which is running in a child shell. Using export to change SCRIPT_HOME in the parent shell would at best be duct-taping the issue, but even this is impossible. Also note that the installation script needs to be run using sudo so it cannot be called from the parent shell using source.
It should be possible since package managers like apt do it. Is there a robust way to patch up my approach? How is this usually done, and is there a good guide to writing bash installers?
You can't. Neither can apt.
A package manager will instead just write required data/variables to a file, which are read either by the program itself, by a patch to the program, or by a wrapper.
Good examples can be found in /etc/default/*. These are files with variable definitions, and some even helpfully describe where they're sourced from:
$ cat /etc/default/ssh
# Default settings for openssh-server. This file is sourced by /bin/sh from
# /etc/init.d/ssh.
# Options to pass to sshd
SSHD_OPTS=
You'll notice that none of the options are set in your current shell after installing a package, since programs get them straight from the files in one way or another.
The only way to modify the current shell is to source a script. That's unavoidable, so start there. Write a script that is sourced. That script will in turn call your current script.
Your current script will need to communicate with the sourced one to tell it what to change. A common way is to echo variable assignments that can be directly executed by the caller. For instance:
printf 'export SCRIPT_HOME=%q\n' "$SCRIPTPATH"
Using printf with %q ensures any special characters will be escaped properly.
Then have the sourced script eval the inner script.
eval "$(sudo install-script.sh)"
If you want to hide the sourceing of the top script you could hide it behind an alias or shell function.

Setting path variables and running Ruby script

This is my first time working with a Ruby script, and, in order to run this script, I have to first cd into the root of the project, which is /usr/local/bin/youtube-multiple-dl and then execute the script as bin/youtube-multiple-dl.
I tried setting the PATH variable
echo 'export PATH="$HOME/youtube-multiple-dl/bin:$PATH"' >> ~/.bash_profile
in hopes that I can run this from anywhere on the machine without having to cd to the project's root, however, no luck with that so far.
System: Ubuntu 15.04 server
Script Repo
My current way of executing the script is:
root#box15990:~# cd /usr/local/bin/youtube-multiple-dl
root#box15990:/usr/local/bin/youtube-multiple-dl# bin/youtube-multiple-dl
Desired way of executing script:
root#box15990:~# youtube-multiple-dl
How can I properly set the enviroment path for this script in order to run from anywhere?
echo 'export PATH="$HOME/youtube-multiple-dl/bin:$PATH"' >> ~/.bash_profile
isn't how we set a PATH entry.
The PATH is a list of directories to be searched, not a list of files.
Typically, the PATH should contain something like:
/usr/local/bin:/usr/bin
somewhere in it.
If it doesn't, then you want to modify it using a text editor, such as nano, pico or vim using one of these commands:
nano ~/.bash_profile
pico ~/.bash_profile
vim ~/.bash_profile
You probably want one of the first two over vim as vim, while being extremely powerful and one of the most-used editors in the world, is also not overly intuitive if you're not used to it. You can use man nano or man pico to learn about the other too.
Once your in your file editor, scroll to the bottom and remove the line you added. Then find the /usr/bin section in your PATH and add /usr/local/bin: before it. : is the delimiter between directories. That change will tell the shell to look in /usr/local/bin before /usr/bin, so that any things you added to the /usr/local/bin directory will be found before the system-installed code, which is in /usr/bin.
It's possible that there isn't a PATH statement in the file. If you don't see one, simply add:
export PATH=/usr/local/bin:$PATH
After modifying your ~/.bash_profile, save the file and exit the editor, and then restart your shell. You can do that by exiting and re-opening a terminal window, or by running:
exec $SHELL
at the command-line.
At that point, running:
echo $PATH
should reflect the change to your path.
To confirm that the change is in effect, you can run:
which youtube-multiple.dl
and you should get back:
/usr/local/bin/youtube-multiple.dl
At that point you should be able to run:
youtube-multiple.dl -h
and get back a response showing the built-in help. This is because the shell will search the path, starting with the first defined directory, and continue until it exhausts the list, and will execute the first file matching that name.
Because of the difficulties you're having, I'd strongly recommend reading some tutorials about managing a *nix system. It's not overly hard to learn the basics, and having an understanding of how the shell finds files and executes them is essential for anyone programming a scripting language like Ruby, Python, Perl, etc. We're using the OS constantly, installing files for system and user's use, and doing so correctly and safely is very important for the security and stability of the machine.

Set a temporary environment ($PATH)

I may fall into a X-Y problem with this question and I encourage you guys to correct me if I am wrong.
I would like to configure a toolchain environment that can work on different platforms and compiler versions. I initially wrote a long Perl script that generates a configuration Makefile that contain only variables. I wanted to be simple so I did not write anything complex using automake or autoconf. Moreover I wanted the reconfiguration process to be very fast. In my case my own written ./configure does everything in less than a second. I am very happy with that.
However I feel I can use a better approach using environment variables. Instead of writing a Makefile with the specific variables I can set the current shell environment directly. For example:
export cc=gcc
Unfortunately, some variables are already declared in the $PATH. The solution is to add the new $PATH in the front of the other:
export PATH=/new/toolchain/path:$PATH
echo $PATH
/new/toolchain/path:/old/toolchain/path:/usr/bin:/bin...
I feel this is ugly I would like to remove the old path before adding the new one.
To conclude:
Is it better to use the environment instead of custom makefiles to set a build configuration?
How to properly adjust existing environment variables?
When I have several variables to set, I write a wrapper script which I then use as a prefix to the command that I want to modify. That lets me use the prefix either
applying to a single command, such as make, or
initializing a shell, so that subsequent commands use the altered settings.
I use wrappers for
setting compiler options (such as clang, to set the CC variable, making configure scripts "see" it as the chosen compiler),
setting locale variables, to test with POSIX C versus en_US versus en_US.UTF-8, etc.
testing with reduced environments, such as in cron.
Each of the wrappers does what is needed to identify the proper PATH, LD_LIBRARY_PATH, and similar variables.
For example, I wrote this ad hoc script about ten years ago to test with a local build of python:
#!/bin/bash
ver=2.4.2
export TOP=/usr/local/python-$ver
export PATH=$TOP/bin:$PATH
export LD_LIBRARY_PATH=`newpath -n LD_LIBRARY_PATH -bd $TOP/lib $TOP/lib/gcc/i686-pc-linux-gnu/$ver`
if test -d $TOP
then
exec $*
else
echo no $TOP
exit 1
fi
and used it as with-python-2.4.2 myscript.
Some wrappers simply call another script.
For example, I use this wrapper around the configure script to setup variables for cross-compiling:
#!/bin/sh
# $Id: cfg-mingw,v 1.7 2014/09/20 20:49:31 tom Exp $
# configure to cross-compile using mingw32
BUILD_CC=${CC:-gcc}
unset CC
unset CXX
TARGET=`choose-mingw32`
if test -n "$TARGET"
then
PREFIX=
test -d /usr/$TARGET && PREFIX="--prefix=/usr/$TARGET"
cfg-normal \
--with-build-cc=$BUILD_CC \
--host=$TARGET \
--target=$TARGET \
$PREFIX "$#"
else
echo "? cannot find MinGW compiler in path"
exit 1
fi
where choose-mingw32 and cfg-normal are scripts that (a) find the available target name for the cross-compiler and (b) provide additional options to the configure script.
Others may suggest shell aliases or functions. I do not use those for this purpose because my command-line shell is usually tcsh, while I run these commands from (a) other shell scripts, (b) directory editor, or (c) text-editor. Those use the POSIX shell (except of course, for scripts requiring specific features), making aliases or functions of little use.
You can create an individualized environment for a particular command invocation:
VAR1=val1 VAR2=val2 VAR3=val3 make
I find this cleaner than doing:
export VAR1=val1
export VAR2=val2
export VAR3=val3
make
unless you're in a wrapper script and maybe even then as with
VAR1=val1 VAR2=val2 VAR3=val3 make the VAR variables will be whatever they were before the make invocation (including but not limited to unexported and nonexistent).
Long lines is a non-issue, you can always split it across several lines:
VAR1=val1\
VAR2=val2\
VAR3=val3\
make
You can set up environment variables like this for any Unix command.
The shell will all set it up.
Some applications (such as make or rake) will modify their environment based on arguments that look like variable definitions (see prodev_paris's answer), but that depends on the application.
Is it better to use the environment instead of custom makefiles to set a build configuration?
The best practice for build systems is to not depend on any environment variables at all. So that nothing more is necessary to build your project than:
git clone ... my_project
make -C my_project
Having to set environment variables is error prone and may lead to inconsistent builds.
How to properly adjust existing environment variables?
You may not need to adjust those at all. By using complete paths to tools like compilers you disentangle your build system from the environment.
As we all know, it is preferrable to integrate standard tools for a task like building your products instead of creating your own approach. The effort usually pays off in the long term.
That being said, a simple approach would be to define different environment files (e.g. build-phone.env) setting working directory, PATH, CC etc. for your different products and source your environment files interactively on demand:
. /path/to/build-phone.env
[your build commands]
. /path/to/build-watch.env
[your build commands]
I think you may benefit from using direct variable definition when you call your makefile, like in the following:
make FOO=bar target
Where FOO is the variable you want to set with value bar.
Note that in this case it take precedence over environment definition! So you can easily override your PATH variable...
Please have a look at this detail topic for more info: https://stackoverflow.com/a/2826178/4716013

How can I change the binary file link to something else

I have two questions and they are linked. I execute the command like this:
python on the shell and it opens the shell.
Now I want
To which file it is linked. I mean when I run python then what is the path of file it opens like /usr/bin/python or what?
The other questions is I want to change that link to some other location so that when I run python then it opens /usr/bal/bla/python2.7.
The command run when you type python is determined primarily by the setting of your $PATH. The first executable file called python that is found in a directory listed on your $PATH will be the one executed. There is no 'link' per se. The which command will tell you what the shell executes when you type python.
If you want python to open a different program, there are a number of ways to do it. If you have $HOME/bin on your $PATH ahead of /usr/bin, then you can create a symlink:
ln -s /usr/bal/bla/python2.7 $HOME/bin/python
This will now be executed instead of /usr/bin/python. Alternatively, you can create an alias:
alias python=/usr/bal/bla/python2.7
Alternatively again, if /usr/bal/bla contains other useful programs, you could add /usr/bal/bla to your $PATH ahead of /usr/bin.
There are other mechanisms too, but one of these is likely to be the one you use. I'd most probably use the symlink in $HOME/bin.

Resources