Is there a way to prepend a command with a variable assignment like in bash? - fish

In bash one can write
CFLAGS="-O2" rvm install 2.0.0
to run rvm with that specific CFLAGS . Is there anyway to do the same in fish shell?
I know about set -x but that is not exactly the same as the environment variable will be set for the whole session instead of just for that command.

According to the fish FAQ, either use:
env CFLAGS="-O2" rvm install 2.0.0
(which will not work for fish builtins or functions, only external commands), or
begin
set -lx CFLAGS="-O2"
rvm install 2.0.0
end
(which is a little clunky; there are proposals for improvement on GitHub issue #438).

You can use the env command for this:
env FOO=BAR command
Will run command with env variable FOO set to BAR.

Related

How to switch NVM environments within perl

I am writing a perl script, and I want to run a simple shell command to use a certain version of NVM:
Here is my code snippet:
print "\n*** Switching to correct nvm environment for dashboard builds\n";
system("nvm use 8.12.0") == 0 or die $?;
But I am getting the following error:
Can't exec "nvm": No such file or directory
Can someone help?
Update (June 30, 2021):
I also tried adding the command:
my $nvm_version = "8.12.0";
system ("bash", "-lic", "nvm use $nvm_version");
But nothing happens:
I'm not familiar with nwm, but I think I get the gist of what it does. And if so, the attempt is fundamentally flawed. Even if you fixed this to run the proper shell so that nvm could run, I believe all the tool does is change the shell's environment variables, a shell you immediately exit. This means it would have no effect even if if it ran successfully.
Again, it this tool does what I think it does, such tool are meant to be used in interactive shells. In other instances, you simply use the path the to correct executable instead of relying on the PATH.
With that in mind, you can use the following to run the command in bash:
# Non-interactive shell.
system("bash", "-c", "nvm use 8.12.0")
or
# Interactive shell.
# This is improper and fragile as interactive shells
# often create aliases that override basic commands.
system("bash", "-ic", "nvm use 8.12.0")
Just to reiterate, at least one of these will allow the command to run (if it normally works from bash), but I believe it's unlikely this will produce the results you expect.
The nvm command is shell function which is different from a shell command. Also the nvm command is not an exported function so it will not be seen by sub shells. For example, in Bash shell:
$ nvm ls
-> v15.0.1
$ my-test-script.sh
./my-test-script.sh: line 3: nvm: command not found
where my-test-script.sh is:
#! /bin/bash
nvm use 16.4
The error nvm: command not found is because nvm is not exported. I can source the script in the current shell context to make it work:
$ source my-test-script.sh
Now using node v16.4.0 (npm v7.18.1)
$ node --version
v16.4.0
So a Perl script cannot change the node version of the current shell, but it can calculate the version and pass it back to shell, which can set the version. For example:
$ nvm use $(perl -E'$v=15.0; print $v')
Now using node v15.0.1 (npm v7.0.3)

Pyenv cannot switch Python versions

I have pyenv installed, however, it does not do its most basic function, namely switch Python versions. The following terminal commands demonstrate this.
the file `main.py` is equivalent to:
import sys
print (sys.version)
Admins-MacBook-Pro-4:kylefoley kylefoley$ pyenv versions
system
* 2.7.14 (set by PYENV_VERSION environment variable)
3.5.3
3.6.1
3.7.3
pypy3.6-7.1.1
Admins-MacBook-Pro-4:kylefoley kylefoley$ pyenv global 3.5.3
Admins-MacBook-Pro-4:kylefoley kylefoley$ pyenv exec python main.py
2.7.14 (default, Oct 17 2019, 00:01:43)
As you can see when I run main.py the version that comes out is 2.7. A lot of people have this problem. One common solution is putting
eval "$(pyenv init -)"
On the bash_profile which I have done and that did not help. Over here
Cannot switch Python with pyenv
it is recommended:
Put the PATH and shell environment vars into your .bash_profile (or whatever file your distro uses).
But what PATH and what shell environment vars is he talking about?
Also my .bashrc file looks like this:
export PATH="/Users/kylefoley/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
Any help would be appreciated. One other things, when I run the following commands, I get the following output:
Admins-MacBook-Pro-4:kylefoley kylefoley$ python
Python 3.6.1rc1 (default, Mar 4 2017, 22:58:58)
The problem is that .bashrc is not sourced in a non-login mode.
Init files for Bash:
login mode:
/etc/profile
~/.bash_profile, ~/.bash_login, ~/.profile (only first one that exists)
interactive non-login:
/etc/bash.bashrc (some Linux; not on Mac OS X)
~/.bashrc
non-interactive:
source file in $BASH_ENV
And on macOS, the default Bash shell opened by a terminal app is a interactive login shell, but on Linux, the default shell opened by a terminal app is a interactive non-login shell.
Solution
The weird interactive, non-login loading requirement confuses people in other situations as well. The best solution is to change the loading requirement of ~/.bashrc as interactive only, which is exactly most of the Linux distros are doing.
# write content below into ~/.bash_profile
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
This should be the solution you desire. And I recommend every Bash user setup this in the profile.
References
Unix shell initialization
Everything was done correctly, it's just that I thought the terminal command . ~/.bash_profile updates the bash profile without having to close the terminal or open a new one in order for changes to take effect. It turns out that . ~/.bash_profile only updates some of the bash_profile. After restarting the terminal, everything was working as planned.
Just add to your .bashrc or similar file, the line.
eval "$(pyenv init --path)"
After the "export PATH=$PYENV..." . Don't forget to reset your terminal after try again!
Worked on Fedora & Mint.
Just add this into you .bashrc file:
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH"
If your .bashrc is sourced from ~/.bash_profile you are done.
Official docs https://github.com/pyenv/pyenv#advanced-configuration suggests puting into .bashrc:
eval "$(pyenv init -)"
which was not working for me.
1.) configure:
pyenv global [python version]
2.)restart terminal (close all terminal windows)

Recommended way to run commands after installing dependencies in the virtualenv

I would like to use tox to run py.test on a project which needs additional setup in addition to installing packages into the virtualenv. After creating the virtualenv and installing dependencies, some commands need to be run.
Specifically I'm talking about setting up a node and npm environment using nodeenv:
nodeenv --prebuilt -p
I see that tox allows me to provide a custom command used for installing dependencies by setting install_command in tox.ini. But I don't think this is what I want because that replaces the command (I assume pip) used to install dependencies.
I thought about using a py.test fixture with session scope to handle setting up nodeenv but that seems hacky to me as I don't want this to happen when py.test is run directly, not via tox.
What is the least insane way of achieving this?
You can do all necessary setup after the creation of the virtualenv and the dependency installation in commands. Yes, it says "the commands to be called for testing." but if you need to do extra work to prepare for testing you can just do it right there.
It works through whatever you throw at it in the order it is given - e.g.:
[testenv:someenv]
deps =
nodeenv
pytest
flexmock
commands =
nodeenv --prebuilt -p
; ... and whatever else you might need to do
py.test path/to/my/tests
If you have commands/scripts or whatever else that produces the right result but it returns a non zero exit status you can ignore that by prepending - (as in - naughty-command).
If you need more steps to happen you can wrap them in a little (Python) script and call that script instead as outlined in https://stackoverflow.com/a/47834447/2626627.
There is also an issue to add the ability to use more than one install command: https://github.com/tox-dev/tox/issues/715 is implemented.
I had the same issue, and as it was important for me to be able to create the environment without invoking the tests (via --notest), I wanted the install to happen in the install phase and not the run phase, so I did something slightly differently. First, I created a create-env script:
#!/usr/bin/env sh
set -e
pip install $#
nodeenv --prebuilt --python-virtualenv --node=8.2.1
Made it executable, Then in tox.ini:
[tox]
skipsdist = True
[testenv]
install_command = ./create-env {opts} {packages}
deps = nodeenv
commands = node --version
This complete example runs and outputs the following:
$ tox
python create: .../.tox/python
python installdeps: nodeenv
python installed: nodeenv==1.3.0
python runtests: PYTHONHASHSEED='1150209523'
python runtests: commands[0] | node --version
v8.2.1
_____________________________________________________________________ summary ______________________________________________________________________
python: commands succeeded
congratulations :)
This approach has the downside that it would only work on Unix.
In tox 715, I propose the possibility of native support for multiple install commands.

Install Perl module with assume yes for given options non-interactively

Normally in linux Debian we do sth like this to install a package non-interactively e.g
sudo apt-get install -y Package_x_z
#[-y --assume-yes]
How we can do the same while installing a perl module e.g
sudo perl -MCPAN -e 'install DBI'
That prompt is (typically) coming from ExtUtils::MakeMaker's prompt() function. Stick export PERL_MM_USE_DEFAULT=1 in your .bashrc (or equivalent for your preferred shell) to stop the prompts. The ExUtils::MakeMaker man page documents it thus:
PERL_MM_USE_DEFAULT
If set to a true value then MakeMaker's prompt function will always return the default
without waiting for user input.
Note that this can come to bite you if you run cpan(1) on a box that's not yet had CPAN repositories configured. It will rattle on and get stuck in a prompt loop at a point where there is no default and you need to make a choice, but have no ability to do so. export PERL_MM_USE_DEFAULT=0 in the shell before running cpan(1) will of course temporarily re-enable input.
To prevent the CPAN client from asking whether to install prerequisites, start it in interactive mode
perl -MCPAN -e shell
and enter the commands:
o conf build_requires_install_policy yes
o conf prerequisites_policy follow
o conf commit
The commit command is optional, but it will update the default configuration, which I suspect is what you want. Without it, you may or may not (depending on whether autocommit is enabled in your CPAN config) need to make this change every time you want to do a prompt-less installation.
These changes will deal with all of the CPAN client's routine questions about whether to install dependencies. For distributions which have questions embedded in their install scripts, you may also want to add
o conf inactivity_timeout 60
to set how long it will wait for a response before automatically going with the default answer to the question. (Set it to 0 to change it back to "wait forever".)
What about just :
$ yes | sudo perl -MCPAN -e 'install DBI'
Ban ! your problem is solved :-)
Appending to an answer here, you can also make these changes in config file located at /usr/share/perl5/CPAN/Config.pm.
'build_requires_install_policy' => q[yes],
'prerequisites_policy' => q[follow],
This helped me to automate installation, since CPAN doesn't have these configuration by default.

running ipython in non-interactive mode

I was hoping it would be easy to rewrite a few bash scripts using ipython by using the "!" command. Unfortunately if I try to run ipython in non-interactive mode like so:
ipython -p sh myipythonscript.py
where myipythonscript.py contains commands like:
env=%env
d=!ls
This doesn't work. I get SyntaxError.
Is there an option which allows ipython to be run in non-interactive mode?
Python also has modules which makes it easy to completely replace bash calls. these are easier to debug and give better error handling.
for example instead of ls you can use glob, it supports the same syntax:
files=glob.glob('myfiles*.txt')
for environment variables:
env = os.environ
for path related functions:
os.path
for common operations, os.mkdir, os.chmod, os.getcwd [same as pwd]