有没有办法在 wsl 中访问 Windows 环境变量?

Rya*_*yan 11 environment-variables windows-subsystem-for-linux

我想在我的 setup.bash 脚本中添加这样的东西。

ln -s /mnt/c/Users/Ryan/Downloads $HOME/Downloads
Run Code Online (Sandbox Code Playgroud)

但显然事实并非总是准确的路径,所以我希望能够做的事情一样

ln -s /mnt/c/Users/%USERNAME%/Downloads $HOME/Downloads
Run Code Online (Sandbox Code Playgroud)

或者

ln -s %USERPROFILE%/Downloads $HOME/Downloads
Run Code Online (Sandbox Code Playgroud)

我知道,很明显的Windows%瓦尔在bash是行不通的,但如果能WSL这将是冷静/不出口这些瓦尔作为$Win32.HOME$Win32.USER什么的。

有什么想法吗?

有没有办法做到这一点?

Ric*_*ner 9

请记住,评估环境变量是 shell 的工作,并且由于您可以在 WSL 上的 Linux 中调用 Windows exe,因此您可以要求 Windows shell(Cmd 或 PowerShell)扩展 Windows env-var。以下是使用 Cmd 执行此操作的方法:

$ cmd.exe /c echo %username%
richturn
$
Run Code Online (Sandbox Code Playgroud)

或者,如果您愿意,您可以选择将一些 Windows 环境变量投影到 WSL 中:)

  • 默认情况下,WSL 将 Windows 路径附加到 Linux 路径,允许您从 Linux 命令行执行 Windows 路径上的任何 .exe(只需确保指定 .exe 扩展名 - 单独使用“cmd”是行不通的! )。有关如何配置的更多信息,请访问:https://docs.microsoft.com/en-us/windows/wsl/interop#wslenv-flags (2认同)

Rya*_*rad 3

这是我所做的:

由于 WSL 现在在 Windows 和 WSL 之间具有互操作性,因此我利用了这一点。

我的~/文件夹中有一个 powershell 脚本,名为~/.env.ps1

# Will return all the environment variables in KEY=VALUE format
function Get-EnvironmentVariables {
    return (Get-ChildItem ENV: | foreach { "WIN_$(Get-LinuxSafeValue -Value ($_.Name -replace '\(|\)','').ToUpper())='$(Convert-ToWSLPath -Path $_.Value)'" })
}

# converts the C:\foo\bar path to the WSL counter part of /mnt/c/foo/bar
function Convert-ToWSLPath {
    param (
        [Parameter(Mandatory=$true)]
        $Path
    )
    (Get-LinuxSafeValue -Value (($Path -split ';' | foreach {
        if ($_ -ne $null -and $_ -ne '' -and $_.Length -gt 0) {
            (( (Fix-Path -Path $_) -replace '(^[A-Za-z])\:(.*)', '/mnt/$1$2') -replace '\\','/')
        }
    } ) -join ':'));
}

function Fix-Path {
    param (
        [Parameter(Mandatory=$true)]
        $Path
    )
    if ( $Path -match '^[A-Z]\:' ) {
        return $Path.Substring(0,1).ToLower()+$Path.Substring(1);
    } else {
        return $Path
    }
}

# Ouputs a string of exports that can be evaluated
function Import-EnvironmentVariables {
    return (Get-EnvironmentVariables | foreach { "export $_;" }) | Out-String
}

# Just escapes special characters
function Get-LinuxSafeValue {
    param (
        [Parameter(Mandatory=$true)]
        $Value
    )
    process {
        return $Value -replace "(\s|'|`"|\$|\#|&|!|~|``|\*|\?|\(|\)|\|)",'\$1';
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我有了这个,在我的.bashrc我有类似以下内容:

function winenv() {
    echo $(powershell.exe -Command "Import-Module .\.env.ps1; Import-EnvironmentVariables") | sed -e 's|\r|\n|g' -e 's|^[\s\t]*||g';
}

eval $(winenv)
Run Code Online (Sandbox Code Playgroud)

我发现,对此需要注意的是,我必须.env.ps1在该命令中输入完整路径。我为此编写了一个函数,将 wsl 样式路径转换回 windows 路径。然后用它来翻译它。

CMD_DIR=$(wsldir "/mnt/c/Users/$USER/AppData/Local/lxss$HOME/\.env.ps1")

因为这是加载环境变量的函数,所以在某种程度上我必须对完整路径进行硬编码。我最终确实在 bash 中设置了一个名为的环境变量LXSS_ROOT=/mnt/c/Users/$USER/AppData/Local/lxss,然后使用了它。


然后,当我启动一个新的 shell 并运行时,env我得到以下信息:

WIN_ONEDRIVE=/mnt/d/users/rconr/onedrive
PATH=~/bin:/foo:/usr/bin
WIN_PATH=/mnt/c/windows:/mnt/c/windows/system32
Run Code Online (Sandbox Code Playgroud)

我现在可以添加类似的东西ln -s "$WIN_ONEDRIVE" "~/OneDrive"到我的.bashrc

对于您的示例,您将这样做:

ln -s $WIN_USERPROFILE/Downloads $HOME/Downloads
Run Code Online (Sandbox Code Playgroud)

此外,我随后在 bin 路径中创建了一个名为 的脚本powershell

# gets the lxss path from windows
function lxssdir() {
    if [ $# -eq 0 ]; then
        if echo "$PWD" | grep "^/mnt/[a-zA-Z]/" > /dev/null 2>&1; then
            echo "$PWD";
        else
            echo "$LXSS_ROOT$PWD";
        fi
    else
        echo "$LXSS_ROOT$1";
    fi
}

PS_WORKING_DIR=$(lxssdir)
if [ -f "$1" ] && "$1" ~= ".ps1$"; then
    powershell.exe  -NoLogo -ExecutionPolicy ByPass -Command "Set-Location '${PS_WORKING_DIR}'; Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Get-Content $1))) ${*:2}"
elif [ -f "$1" ] && "$1" ~!= "\.ps1$"; then
    powershell.exe -NoLogo -ExecutionPolicy ByPass -Command "Set-Location '${PS_WORKING_DIR}'; Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Get-Content $1))) ${*:2}"
else
    powershell.exe -NoLogo -ExecutionPolicy ByPass ${*:1}
fi
unset PS_WORKING_DIR
Run Code Online (Sandbox Code Playgroud)

所以我可以做这样的事情:

$ powershell ~/my-ps-script.ps1
$ powershell -Command "Write-Host 'Hello World'"

我确信所有这些都可以进行改进。但是,它目前适用于我的场景。

这是我使用的脚本的要点。