I tried this on OS X
> $env:PATH
/usr/bin:/bin
It doesn't have /usr/local/bin
in PATH
So I cannot run powershell
(and gitk
, which really was my motivation)
/usr/local/bin
should be there
powershell should be able to run apps from it, i.e. gitk
, powershell
Cannot run powershell
v0.3.0
OS X sets up default paths for shells by calling out to path_helper
. Bash (and Zsh, and Csh) all execute
eval `/usr/libexec/path_helper -s`
in their respective /etc/profile
files. The OS Xy way for PowerShell to do this would be to add a similar call to our system profile.
However, path_helper
was of course not designed with PowerShell in mind, and so it only can emit the PATH
and MANPATH
variables in two styles, C-shell and Bourne shell. We don't really have much of an option but to parse its output and reinterpret it for PowerShell.
It's easy: string PATH = MANPATH.Replace(':', ';');
:)
Also, it screws up Start-PSBootstrap
(on OS X), because it uses installer
vors@Sergeis-MacBook ~/d/fzf> whereis installer
/usr/sbin/installer
Meanwhile, here is a one-liner that you can add to the profile to fix it
$path_helper = /usr/libexec/path_helper; if ($path_helper -match '"(.*)"') { $env:PATH = $Matches[1] }
@vors what about MANPATH
?
@andschwa ah, what's with it?
I think this is blocked on PowerShell/PowerShell-RFC#92. Either way, we need to fix it for 6.0.0.
This is no longer blocked on that above RFC: our approach should create a system-level profile on each distro and macOS that runs the PowerShell equivalent of whatever other default shells call in order to build the "login shell" set of environment variables and state.
In other words, we need to have what @vors put above in the default macOS profile.
However, this will break when PowerShell isn't a login shell because we run profiles by default, and the profile would overwrite any environment variables set in a parent bash (or other shell).
@PowerShell/powershell-committee agrees that PowerShell needs to act like other shells, need to understand impact of specifics
@SteveL-MSFT and I think this might just be as simple as invoking /etc/profile when in a login shell scenario and to copy the environment variables that get generated back into PowerShell.
Would love some domain-expertise from @mklement0 if you're around. 馃槃
Context here: https://unix.stackexchange.com/questions/38175/difference-between-login-shell-and-non-login-shell
@joeyaiello:
Happy to chime in, but to be clear about what I can contribute: I know macOS pretty well; my go-to Linux platform for contrasting macOS with Linux is Ubuntu; however, I don't have a good sense of what's standard / typical across _all_ major Linux distros.
The issue at hand is not macOS-specific; Fedora (and, I presume, RedHat) also adds directories to $PATH
in /etc/profile
- despite that fact that Fedora and Ubuntu (others?) have a separate, shell-independent file for defining system-wide environment variables, /etc/environment
.
On Ubuntu, it is the latter that makes $PATH
additions.
_Update: This is likely not a problem in LOCAL sessions, but would be with ssh
- see below_.
Login shells - if they're POSIX-compatible - _de facto_ source /etc/profile
_and_ $HOME/.profile
- though I couldn't find evidence of that as a _requirement_ in the POSIX spec. (did I miss it?) - $HOME/.profile
is mentioned as "typically executed" in http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html, but there's no mention of /etc/profile
; bash
allows preempting $HOME/.profile
(but not /etc/profile
) with Bash-specific alternatives ($HOME/.bash_profile
(highest precedence) or (rarely used) $HOME/.bash_login
); an overview of the behavior of the major POSIX-like shells (and csh
variants, which I don't think we need to worry about) can be found at https://en.wikipedia.org/wiki/Unix_shell#Configuration_files
What POSIX does mandate is support for the - rarely used - $ENV
variable "if the system supports the User Portability Utilities option" (whatever that means), which may point to a script to be sourced for _any_ interactive shell - whether it is a login shell or not - see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_03.
While this is the closest equivalent to PowerShell's $PROFILE
(given that PowerShell has no concept of login vs. non-login shells), I've never seen it used in practice, and bash
only honors it when it explicitly run in POSIX-compatibility mode.
On Linux, the default shell is called as a _login_ shell _once_, when the user initially logs on to the OS. Seemingly - at least on Ubuntu - a /bin/sh
login shell is always used when a user logs in to the OS, which does process /etc/profile
, and seemingly _all_ user processes (not just shells, and irrespective of whether or not they're POSIX-like shells) then _inherit process-level attributes_ from it, which notably includes environment variables , umask
and ulimit
values; others?
ssh
server component - seemingly do _not_ inherit from this sh
process, which means that remotely accessing a Linux machine with ssh
sees the definitions from /etc/profile
only if the remotely started shell instance itself processes it - which is why ssh
starts the shells used as a _login_ shell.On macOS, _every_ shell instance created via Terminal.app
, the default terminal (and also third-party terminals such as iTerm.app
) is a _login_ shell.
The fundamental question is to what extent PowerShell needs to play by these rules.
/etc/profile
is the most important file, because it contains important environment definitions on macOS, and, as stated, on at least 1 major Linux distro.
On Linux - at least on Ubuntu - that is not a concern for _local_ sessions, for the reasons explained above (all processes inherit the env. variables from /etc/profile
, which is always processed when the user logs on to the OS, and also from /etc/environment
).
ssh
sessions, whose server component itself does not process /etc/profile
, so that shells created remotely via ssh
must process /etc/profile
themselves, which POSIX-like shells do, because ssh
creates _login_ shells, by way of prefixing the invocation name ($0
) with -
, which the shells are expected to honor.On macOS, the ssh
problem applies too, but even local sessions are expected to process /etc/profile
, because local shell processes on macOS do _not_ inherit from a single sh
process that processes /etc/profile
; instead, the terminal programs on macOS create _login_ shells _by default_, every time a shell is instantiated, so if PowerShell is the default shell, the important $PATH
additions - possibly among other initializations - won't happen even for local shells - see https://github.com/PowerShell/PowerShell/issues/6027#issuecomment-360638685
It is debatable whether PowerShell should be expected to honor ~/.profile
or even $ENV
. Arguably, only honoring /etc/profile
is sufficient, as an exception, due to its shell-transcendent importance.
The approach proposed by @joeyaiello is robust with respect to honoring the _environment variables_, but:
it comes with a performance penalty that on macOS _every_ terminal-program created instance will pay (with PowerShell as the default shell); however, it doesn't apply to direct invocation of powershell
.
the honoring may not be complete, as /etc/profile
may contain commands such as umask
and ulimit
(not sure what other commands need to be considered).
For PowerShell to detect being invoked as a _login_ shell it must examine the equivalent of $0
(argv[0]
) - the invocation name - to look for -
as the 1st char., because that is the mechanism used by:
ssh
exec
builtin when a shell is spawned with the -l
option.[Environment]::CommandLine
doesn't reflect such such a custom invocation name, however (it contains the path to PowerShell _DLL_, which is a bug yet to be resolved - see https://github.com/dotnet/coreclr/issues/20562). As a workaround, PowerShell could determine its invocation name via the standard ps
utility, using command ps -o comm= $PID
.
Additionally, the major POSIX-like shells also support explicit invocation with option -l
to create a login shell - PowerShell has no equivalent.
_Update: -l
is now supported - see #9528_
Finally, PowerShell's current startup behavior with respect to profiles (and other aspects) is fundamentally at odds with that of POSIX-like shells in that it loads its profiles _by default_, irrespective of whether the shell is interactive or not (or a login shell, which PowerShell has no concept of) - see #3743
This means, for instance, that with PowerShell as the default shell, (see above).$PROFILE
is also sourced in the invisible login shell instance that is created on OS session startup on Linux.
Really /etc/profile
and ~/.profile
is Bash scripts - we can not directly interprete it in PowerShell. I wonder why we should depend on Bash script files? csh/tcsh use their files (/etc/.login
and ~/.login ). We can do the same and use /etc/powershell.login.json
and ~/.powershell.login.json
files.
@iSazonov:
I've updated my comment above to reflect recent findings:
On _Linux_, given how , _locally created_ shell sessions wouldn't need to process /etc/profile
works there (disclaimer: I've only looked at Ubuntu 16.04), I think we're all set./etc/process
again, but sessions started _remotely_, via ssh
, would.
On _macOS_, _every_ login shell session (whether local or remote) is expected to process /etc/profile
:
sh
, we could implement a workaround based on https://github.com/PowerShell/PowerShell/issues/6027#issuecomment-360638685 for making the important $PATH
additions, though that wouldn't cover other environment variables that users _may_ have added directly to /etc/profile
.As stated, even calling out to sh
and copying the resulting environment variables wouldn't cover other initializations users _may_ have added to /etc/profile
, such as a umask
statement (see https://github.com/PowerShell/PowerShell/issues/6679#issuecomment-383204763) or a ulimit
statement.
Looks like more people are hitting this now. My proposed fix for PS7 is to build on https://github.com/PowerShell/PowerShell/pull/9528 so if -l
is used, pwsh will shell out to sh
and apply those env vars to itself. umask
and other environment factors will not be taken into account pending additional user feedback and addressed case-by-case.
It looks as workaround without RFC defined PowerShell as login shell. Having the RFC Unix distributive maintainers can expose paths in standard way. Ex.: we could have a ps_path_helper utility per Unix distributive and call it at PowerShell login shell startup.
There is a difference between .bash_profile and .profile
https://askubuntu.com/questions/60218/how-to-add-a-directory-to-the-path/226947
I mean that $PATH can be different for login and non-login shells.
Related #10050
:tada:This issue was addressed in #10050, which has now been successfully released as v7.0.0-preview.3
.:tada:
Handy links:
Why does pwsh
not pick up the environment variables from bash
when it is launched??
[mee foo]$ echo $NODE_EXTRA_CA_CERTS
/cafile.pem
[me foo]$ pwsh
PS /foo> $env:NODE_EXTRA_CA_CERTS
Crickets...
@cawoodm If you ask about default shell just this was used in #10050.
@iSazonov, @cawoodm's problem is unrelated to this issue.
@cawoodm, are you sure that $NODE_EXTRA_CA_CERTS
is defined as an _environment_ variable (typically created with export
), and not just as a _shell_ variable? Shell variables aren't seen by child processes.
Try the following (from Bash or any other POSIX-like shell) to verify that a true environment variable is indeed inherited by PowerShell (this syntax creates a command-scoped environment variable):
$ NODE_EXTRA_CA_CERTS=foo pwsh -noprofile -c '$env:NODE_EXTRA_CA_CERTS'
foo
Also note that such inheritance is a system-level feature that exists independently of PowerShell.
If you have a reproducible case where this inheritance indeed doesn't work, please create a new issue.
To me there is no difference: whatever environment variables I have (echo $foo) should be available in child processes like pwsh
. PowerShell should not load some other environment - that would break stuff.
Now, we're using WSL and it does not seem to respect /etc/environment
so we have added the following to .bashrc
:
NODE_EXTRA_CA_CERTS=foo
To be honest I do not know the difference between bar=foo
and export bar=foo
...
Checking it with bash:
$ echo $NODE_EXTRA_CA_CERTS
foo
Good, checking it with pwsh:
$ pwsh -noprofile -c '$env:NODE_EXTRA_CA_CERTS'
Not Good.
My expectation would be that the current environment is passed to pwsh
. I think this is normal behaviour for child processes.
My expectation would be that the current environment is passed to pwsh
_Shell_(-only) variables are not part of the system-level _process environment_, which is the only environment child processes inherit. Shell variables are by design limited to the given shell process.
While in cmd.exe
_all_ variables are environment variables, both PowerShell and POSIX-like shells such as bash
distinguish between shell(-only) variables and environment variables.
While In PowerShell you always use the same, distinct syntax for both creating and querying environment variables ($env:...
), in POSIX like shells _both_ types of variables are _queried_ the same, namely with just the $
sigil, as in $NODE_EXTRA_CA_CERTS
; that is when you _get_ a variable value, the syntax isn't telling you whether you're accessing a _shell_(-only) or an _environment variable_.
In POSIX-like shells, it's the _declaration_ of a variable that matters:
As a _stand-alone statement_, NODE_EXTRA_CA_CERTS=foo
creates a _shell_(-only) variable - by design, no child process will see it.
What I used above - _prepending_ variable assignments directly to a command invocation (NODE_EXTRA_CA_CERTS=foo pwsh ....
) - is _syntactic sugar_ for defining _command-scoped_ environment variables - only the child process created sees them, not the remainder of the script.
If you want to use a stand-alone statement to create an environment variable, use the export
utility:
export NODE_EXTRA_CA_CERTS=foo
In POSIX-like shells:
To see all _environment_ variables, run env
(in PowerShell you'd use Get-ChildItem env:
)
To check whether a given variable is an environment variable, use typeset -p <name>
(works in bash
, ksh
, zsh
): if the output contains either -x
or export
(zsh
), the variable is an environment variable (in PowerShell you'd use Get-Item env:<name>
).
Thanks @mklement0 - you da man!
Most helpful comment
Thanks @mklement0 - you da man!