Eval in fish shell function working strange - fish

I tried to make wrapper to docker's command to change docker machine context. Here's the command and output:
docker-machine env dev
set -x DOCKER_TLS_VERIFY "1";
set -x DOCKER_HOST "tcp://192.168.99.101:2376";
set -x DOCKER_CERT_PATH "/Users/sandric/.docker/machine/machines/dev";
set -x DOCKER_MACHINE_NAME "dev";
# Run this command to configure your shell:
# eval (docker-machine env dev)
Code for function, I placed in .config/fish/config.fish:
function cdm
eval (docker-machine env $argv)
end
So, when trying to run cdm in new session, function evaluated, but context didn't change. If however, I'd run:
eval (docker-machine env default)
from command prompt, and tried to run cdm with different arguments - all works fine. So I suspect that it has smth to do with existing of environment variables this command trying to set from fish function.. I even tried then to experiment and change that function to alias (which is also alias to fish functions as I get) command with constant instead of parameter:
alias cdm "eval (docker-machine env dev)"
And it worked the same - it didn't changed environment variables if I ran this alias first on newly opened session, but if I run eval code from command prompt - after that alias working as expected.
So, whats its all about, anyone have any ideas?

It looks like that Docker's output does not specify an explicit scope, so when you run it inside your function and those variables have not been defined elsewhere, they will end up in the function's scope.
However, if you run the same code from the command prompt, you will end up with variables defined in the global scope, which are then updated by the set in the function.
See the documentation for set:
The scoping rules when creating or updating a variable are:
If a variable is explicitly set to either universal, global or local,
that setting will be honored. If a variable of the same name exists in
a different scope, that variable will not be changed.
If a variable is not explicitly set to be either universal, global or
local, but has been previously defined, the previous variable scope is
used.
If a variable is not explicitly set to be either universal, global or
local and has never before been defined, the variable will be local to
the currently executing function. Note that this is different from
using the -l or --local flag. If one of those flags is used, the
variable will be local to the most inner currently executing block,
while without these the variable will be local to the function. If no
function is executing, the variable will be global.
To fix this problem, try defining your cdm function with --no-scope-shadowing (although this seems to work, I'm not sure that it should).

Related

In powershell, how can I define all env vars for the next command similar to python's Popen abilities?

In powershell, how can I...
explicitly define all the env vars for the next command?
I don't want any system env vars if possible,
After this command runs I dont want anything we have done to affect further processes in the shell.
As an example, in python we have the equivalent ability in Popen to pass a dictionary of the full environment to the subprocess, and I'm hoping there might be something similar in Powershell.
I think this link explains what you need: Windows user environment variable vs. system environment variable
[Environment]::GetEnvironmentVariable("TEMP", "Machine")

Powershell GetEnvironmentVariable vs $Env

I have run into a couple cases where I am trying to use a command via command line, but the command is not recognized. I have narrowed it down to an issue with environment variables. In each case, the variable is present when I retrieve the variable with the underlying C# method, but not with the shorthand, $env:myVariable
For example, if I retrieve the variable like this, I will get a value.
[Environment]::GetEnvironmentVariable('ChocolateyInstall', 'Machine')
But, if I retrieve the variable like this, nothing is returned
$env:ChocolateyInstall
I then have to do something like this to to get my command to work.
$env:ChocolateyInstall = [Environment]::GetEnvironmentVariable('ChocolateyInstall', 'Machine')
I have not been able to find a good explanation as to why I have to do this. I've looked at this documentation, but nothing stands out to me. Ideally, I would like to install a CLI and then not have to deal with checking for and assigning environment variables for the command to work.
When opening a PowerShell session, all permanently stored environment variables1 will be loaded into the Environment drive (Env:) of this current session (source):
The Environment drive is a flat namespace containing the environment
variables specific to the current user's session.
The documentation you linked states:
When you change environment variables in PowerShell, the change
affects only the current session. This behavior resembles the behavior
of the Set command in the Windows Command Shell and the Setenv command
in UNIX-based environments. To change values in the Machine or User
scopes, you must use the methods of the System.Environment class.
So defining/changing an environment variable like this:
$env:ChocolateyInstall = [Environment]::GetEnvironmentVariable('ChocolateyInstall', 'Machine')
Will change it for the current session, thus being immediately effective, but will also only be valid for the current session.
The methods of [System.Environment] are more fine grained. There you can choose which environment variable scope to address. There are three scopes available:
Machine
User
Process
The Process scope is equivalent to the Environment drive and covers the environment variables available in your current session. The Machine and the User scope address the permanently stored environment variables1. You can get variables from a particular scope like this:
[Environment]::GetEnvironmentVariable('ChocolateyInstall', 'Machine')
And set them with:
[Environment]::SetEnvironmentVariable('ChocolateyInstall', 'any/path/to/somewhere', 'Machine')
If you want to have new variables from the Machine or User scope available in your current PowerShell session, you have to create a new one. But don't open a new PowerShell session from your current PowerShell session, as it will then inherit all environment variables from your current PowerShell session (source):
Environment variables, unlike other types of variables in PowerShell,
are inherited by child processes, such as local background jobs and
the sessions in which module members run. This makes environment
variables well suited to storing values that are needed in both parent
and child processes.
So, to address the problem you described, you most probably changed your permanently stored environment variables1, while already having an open PowerShell session. If so, you just need to open a new (really new, see above) session and you will be able to access your environment variables via the Environment drive. Just to be clear, opening a new session will even reload environment variables of the Machine scope. There is no reboot required.
1 That are the environment variables you see in the GUI when going to the System Control Panel, selecting Advanced System Settings and on the Advanced tab, clicking on Environment Variable. Those variables cover the User and the Machine scope.
Alternatively, you can open this GUI directly by executing:
rundll32 sysdm.cpl,EditEnvironmentVariables

Passing environment variables from perl to tcl

I'm a newbie to Perl and Tcl. I'm trying to pass a variable from a Perl script to a Tcl script. I declared the variable as environment variable and trying to pass. But no results. Please find the code below:
Perl side:
$ENV{'output_directory_final'} = "./$Image_name/$Date_release/final";
Tcl side:
set out_path ${output_directory_final};
But, this is not working. Can anyone give any other ideas?
By special dispensation, the global array env in Tcl contains the values of the environment variables for the process. In your case, try something like:
set out_path $env(output_directory_final)
Be mindful that if you are inside a proc, then a global env command is necessary to obtain local access to the variable.

Why would fish appear to ignore the second 'set' command in a function?

When I run this function, JAVA_HOME gets set, JUG_BT_ARCH does not get set, and 'gello' gets echoed. I'm sure I'm missing something really obvious.
function j8
set -x JAVA_HOME /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/
set -x JUG_BT_ARCH amd64-darwin11-xcode4
echo gello
end
Variables by default have function-scope, so when the function ends, they go away. You can make them global via --global or -g:
set -gx JUG_BT_ARCH amd64-darwin11-xcode4
Now when you run the function, this variable will stick around.

supervisor program:x command expansion of environment variables $(ENV_VAR)s?

I would like to put configuration (in this case, site name) into supervisor
environment variables, for expansion in program:x command arguments. Is this supported? The documentation's wording would seem to indicate yes.
The following syntax is not working for me on supervisor-3.0 (excerpt of config file):
[supervisord]
environment = SITE="mysite"
[program:service_name]
command=/path/to/myprog/myservice /data/myprog/%(ENV_SITE)s/%(ENV_SITE)s.db %(program_name)s_%(process_num)03d
process_name=%(program_name)s_%(process_num)03d
numprocs=5
numprocs_start=1
Raises the following error:
sudo supervisord -c supervisord.conf
Error: Format string
'/path/to/myprog/myservice /data/myprog/%(ENV_SITE)s/%(ENV_SITE)s.db %(program_name)s_%(process_num)03d'
for 'command' contains names which cannot be expanded
Reading the documentation, I expected environment variables to be available for
expansion in program:x command as %(ENV_VAR)s:
http://supervisord.org/configuration.html#program-x-section-values
command:
"String expressions are evaluated against a dictionary containing the keys
group_name, host_node_name, process_num, program_name, here (the directory of
the supervisord config file), and all supervisord's environment variables
prefixed with ENV_."
Introduced: 3.0
Related:
There are open pull requests to enable expansion in additional section values:
https://github.com/Supervisor/supervisor/issues?labels=expansions&page=1&state=open
A search of goole (or SO) returns no examples of attempts to use %(ENV_VAR)s
expansion in the command section value:
https://www.google.com/search?q=supervisord+environment+expansion+in+command
I agree supervisor is not clear about this ( to me at least ).
I've found the easiest solution to execute /bin/bash -c.
In your case it would be:
command=/bin/bash -c"/path/to/myprog/myservice /data/myprog/${SITE}/${SITE}.db ..."
What do you think?
I've found inspiration here: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image-inheritance/
You are doing it right; however, the ENV defined in your supervisord section doesn't get made available to the processes for whatever reason during configuration loading. If you start supervisord like this:
SITE=mysite supervisord
It will run correctly and expand that variable. I don't know why supervisord has issues adding to the environment and making it available to the subprocesses' config expansion. I think the environment variable is available inside the subprocess, but not when expanding variables in the subprocess config declaration.