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

时间:2017-05-05 01:03:49

标签: environment-variables windows-subsystem-for-linux

我想在我的setup.bash脚本中添加类似的内容。

ln -s /mnt/c/Users/Ryan/Downloads $HOME/Downloads

但很明显,这并不总是一条准确的路径,所以我希望能够做到 之类的

ln -s /mnt/c/Users/%USERNAME%/Downloads $HOME/Downloads

ln -s %USERPROFILE%/Downloads $HOME/Downloads

我知道很明显,Windows%vars在bash中不起作用,但如果wsl能够/确实将这些变量导出为$Win32.HOME$Win32.USER或其他东西,那将会很酷。

有什么想法吗?

有没有办法做到这一点?

3 个答案:

答案 0 :(得分:1)

这是我做的:

由于WSL现在已经在windows和WSL之间进行了互操作,所以我利用了它。

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

的PowerShell脚本
# 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';
    }
}

现在我有了这个,在.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)

我发现,有一点需要注意的是,我必须在该命令中填写.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

我现在可以在ln -s "$WIN_ONEDRIVE" "~/OneDrive"

中添加.bashrc之类的内容

对于您的示例,您可以这样做:

ln -s $WIN_USERPROFILE/Downloads $HOME/Downloads

此外,我在我的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

所以我可以这样做:

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

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

这是我使用的gist个脚本。

答案 1 :(得分:1)

记住评估环境变量是shell的工作,并且因为你可以在Linux上从WSL调用Windows exe,你可以要求Windows shell(Cmd或PowerShell)扩展Windows env-var。以下是你用Cmd做的事情:

$ cmd.exe /c echo %username%
richturn
$

或者,如果您愿意,可以选择project some of your Windows environment variables into WSL。)

答案 2 :(得分:0)

使用这个简单的bash函数恢复了旧帖子,我决定将其添加到我的/etc/bash.bashrc

winenv()
{
  if [ "$#" == "0" ] || [ "$1" == "--help" ]
  then
    echo $'\n'Usage:
    echo $'\t'winenv [-d] WINDOWS_ENVIRONEMENT_VARIABLE_NAME
    echo $'\t'-d: Defines environment variable in current shell
    echo $'\t'"    "Note that paths will be translated into un*x-like paths$'\n'
    return
  fi
  local IFS='$\n'
  local PATH_TO_TRANSLATE=$1
  [ "$1" == "-d" ] && PATH_TO_TRANSLATE=$2
  local VAR=$(cmd.exe /c echo %${PATH_TO_TRANSLATE}% | tr -d '\r')
  local NEW=$(wslpath -u "${VAR}" 2>/dev/null || echo ${VAR})
  echo "${PATH_TO_TRANSLATE} = ${VAR} -> ${NEW}"
  [ "$1" == "-d" ] && export "${PATH_TO_TRANSLATE}=${NEW}"
}

for EnvVar in 'USERNAME' 'USERPROFILE' 'USERDOMAIN' 'USERDNSDOMAIN' 'WINDIR' 'SystemDrive' 'SystemRoot' 'TNS_ADMIN' 'ORACLE_HOME' 'CLIENT_NAME' 'HOMEDRIVE' 'HOMEPATH' 'TMP' 'TEMP'
do
  winenv -d $EnvVar >/dev/null
done