env and PATH
Federico Kircheis
federico@kircheis.it
Sat Jan 4 21:38:19 GMT 2025
On 04/01/2025 21.13, Andrey Repin wrote:
> Greetings, Federico Kircheis!
>
>> On 04/01/2025 02.41, Andrey Repin wrote:
>>> Greetings, Federico Kircheis!
>>>>> Hello to everyone,
>>>>>> I've noticed that env seems to handle the environment variable PATH in a particular way
>>>>>> -----
>>> >> cd /d;
>>> >> env -i PATH='C:\Windows;C:\Windows\system32;' /c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe
>>>> # in the powershell instance
>>>> echo $env:PATH
>>>> C;D:\Windows;C;D:\Windows\system32;
>>>> ----
>>>> Fully expected behavior. `env` expects POSIX semantics and parsed your
>>> command according to that.
>>> The results are, as I said, expected, although not by you.
>> What do you mean by POSIX semantic?
>> On my Linux system, PATH is used unmodified by subprocesses, not transformed.
>> This is (IMHO) the expected semantic.
>
> No. env is a Cygwin (POSIX) tool and it works with POSIX paths.
> When starting non-POSIX app, Cygwin will translate $PATH back to native
> format.
>
>> I am not aware of any rule in POSIX that requires or recommends some
>> transformations for environment variables, in that sense, any transformation
>> is "unexpected" or an extension to the standard.
>
> That's Cygwin specific.
>
>> It completely makes sense to convert cygwin paths to windows path when
>> invoking windows programs, but it is not my case.
>
> Then why TF you supply Windows paths to it?
Because it is a windows program.
And since I do not have cygwin paths, it does not make sense to convert
them.
>> Hence why I searched for an option, even an explicit one, to tell cygwin
>> not to modify the parameters, but use them as-is.
>
>>>> From this and other examples it seems that env uses for PATH as
>>>> separator, then preprends the current drive to all paths that begin with '\'
>>>> (thus all of them), and ";" is treated as part of the path
>>>> Exactly.
>>>>> I would like to use the PATH as-is in the invoked program, just like it is done for other variables, for example
>>>>> ----
>>>> cd /d
>>>> env -i OPATH='C:\Windows;C:\Windows\system32;'
>>>> /c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe
>>>> # in the powershell instance
>>>> echo $env:OPATH
>>>> C:\Windows;C:\Windows\system32;
>>>> ----
>>>>> in this case OPATH is forwarded as-is to powershell.exe.
>>>>> I understand that PATH is special, that for cygwin processes some transformation might be necessary.
>>>> It is, but in a way you suppose.
>>>>> But is there any way to achieve what I'm trying?
>>>> Yes. Pass the POSIX paths in $PATH, they will be converted to Windows ones
>>> when invoking a Windows process.
>>> Also, I strongly suggest using /proc/cygdrive/ tree in such case, especially
>>> when you make scripts for somebody else.
>
>> I was not aware of /proc/cygdrive/, thank you for the hint, although I am not sure how it helps.
>
>>>> I search if there is maybe a separation option for telling env to use PATH as-is, but could not find none.
>>>> There's no need or reason to do it.
>>>> In your case, what you wanted to achieve could be written as
>>>>>> env -i "PATH=$(cygpath -UW):$(cygpath -US):$PATH" pwsh
>
>> The reason is I already have a variable containing the path I should use as
>> PATH, and it is the windows expected format.
>
> But you just said that your app is NOT a Windows app. Then why do you attempt
> to supply it Windows paths?
No.
I wrote that it is not my case because my PATH does not have cygwin
paths; it has windows paths.
> Then in your example you invoke PowerShell which IS a Windows app.
> So, what was it?
I'm trying to invoke a Windows program, as I wrote since my first mail.
>> I need to convert it to a cygwin path, so that env translates it back again.
>> It is doable, but sounds completely unnecessary.
>
> Nope.
>
>> Also it comes at a particular cost at runtime.
>> I want to start the subshell as fast as possible.
>
> () will start a subshell. As fast as possible.
Sorry, I meant a windows subshell; for example cmd and powershell.
>> Iterating and invoking an external program (cygpath) for every path takes some time.
>
> Depends on actual use case, it may be just a single invocation for entire
> list.
I'm currently not on Windows, you mean it is possible to convert
C:\Windows;C:\Windows\system32;
to
/cygdrive/c/windows:/cygdrive/c/windows/system32
(or equivalent with /proc) with one invocation of cygpath?
If that is the option --path (just read from the documentation, I did
not notice it before, and did not try it, I will do it in the next days)
then I suppose the performance issue I mentioned would be a non-issue.
Although I would still have preferred to be able to tell env to use the
variable as-is, just like all the others.
> But let's stop there and settle the matter of what we are doing and what is
> the expected result.
The use-case is starting a windows shell (powershell, cmd, ...) with a
provided environment, from cygwin.
For example an environment without TERM, without cygwin tools in PATH,
and so on.
The easiest way to do it is to use env, ignore all environment
variables, and provide the desired one.
The "issue" is that in case of PATH (and maybe other env variables? so
far PATH is the only one I observed), the provided values are modified
before the windows executable (powershell, cmd, ..) is invoked.
This conversion is normally fine, because PATH usually contains cygwin
paths, but it is not my case; PATH contains windows paths, thus the
translation is not necessary and actually hurtful.
>>> (The "%SystemRoot%" is NOT NECESSARILY 'C:\Windows', though you CAN use
>>> "%SystemRoot%\System32" with confidence, once you acquired the former.)
>>> (Also, why the *** you are using v1.0? Get v7 already, save yourself the
>>> tragedy.)
>
>> Because the executable I invoked is the one installed on all Windows
>> versions since Windows 7 (or maybe even Vista?).
>> Also the actual version is not 1.0, but something like 5.something (if I remember correctly)
>
> Yes, it's more like v5 at the moment.
>
>> v7 is AFAIK a different product, but most importantly it needs to be
>> installed separately, and would not change the issue I have.
>
> But it's infinitely more powerful.
> Bonus: /usr/local/bin/pwsh
>
>>> #!/bin/sh
>>>
>>> if [ "$1" ] && [ -f "${_cmd:="$( cygpath -am -- "$1" )"}" ]; then
>>> shift
>>> else
>>> unset _cmd
>>> fi
>>>
>>> if [ "$_cmd" ]; then
>>> "$PROGRAMFILES/PowerShell/7/pwsh.exe" "-NoLogo" "-File" "$_cmd" "$@"
>>> else
>>> "$PROGRAMFILES/PowerShell/7/pwsh.exe" "-NoLogo" "$@"
>>> fi
More information about the Cygwin
mailing list