windows bash shell访问$ProgramFiles(x86)环境变量

kninwzqo  于 2023-04-13  发布在  Windows
关注(0)|答案(3)|浏览(149)

在bash shell中,我使用git-bash.exe,如何访问Windows 10 ProgramFiles(x86)环境变量?
如果我执行printenv,我会在输出中看到它,并标注了大小写,但尝试使用echo $ProgramFiles(x86)echo $ProgramFiles\(x86\)echo $"ProgramFiles(x86)"访问它时不起作用。
我能够使用echo $PROGRAMFILES访问该环境变量的非x86版本而没有任何问题,并执行相关的冒号删除和反斜杠以在PATH环境变量更新中使用它所需的前向替换,例如,PATH=$PATH:"/${PROGRAMFILES//:\\//} (x86)/Some App Path With Spaces/"后面跟着echo $PATHprintenv PATH,这确认了所需的结果。问题是我宁愿不必编写ProgramFiles(x86)环境变量与能够在PATH环境变量的更新中直接使用它之间的差异。
沿着,当尝试在PATH环境变量的更新中使用Windows APPDATA [ = C:\Users<username〉\AppData\Roaming ]环境变量时,我不仅需要能够将初始冒号和反斜杠替换为正斜杠,还需要能够将随后的反斜杠替换为正斜杠。我不知道如何让bash环境变量的字符匹配和替换语法涵盖这两种情况,以产生所需的C/Users/<username>/AppData/Roaming,用于更新PATH环境变量。

jckbn6z7

jckbn6z71#

注意:在下面描述的过程中有一个缺陷。特别是,如果某个环境变量被设置为多行值,其中一行值与sed表达式匹配,那么你也会捕获该行。为了避免这种情况,如果你有Python可用,你可以用途:

python -c 'import os; print(os.getenv("FOO(BAR)"))'

例如,如果变量没有设置,它将打印None,所以你可能想让它更漂亮:例如,提供一个默认值,或者如果变量没有设置,则使用sys.exit(1)(但如果您有可用的Python解释器,则可以考虑使用Python编写,而不是直接使用bash)。
Unix shell(sh,bash等)变量名(包括环境变量)被限制为不包括圆括号的字符集。特别是,"$FOO(BAR)" * 总是 * 解析为对变量$FOO的引用,后跟(BAR)作为单独的单词。即使在括号扩展形式中,单独的单词(BAR)在语法上也是无效的:

bash$ echo "${FOO(BAR)}"
bash: ${FOO(BAR)}: bad substitution

尽管如此,我们还是有可能使用其他程序来设置和访问这些变量,例如,使用Python我将FOO(BAR)设置为hello

>>> import os
>>> os.environ["FOO(BAR)"] = "hello"
>>> import subprocess
>>> subprocess.call("bash")
bash$

这个bash示例不能直接访问变量,但是env打印了所有的变量:

bash$ env | grep FOO
FOO(BAR)=hello

如果你有env(你可能有)和sed,你可以合并它们来提取任意变量:

bash$ setting="$(env | sed -n 's/^FOO(BAR)=//p')"
bash$ echo "$setting"
hello

因此,假设Windows Bash没有任何特殊的情况来更好地解决这个特定的笨拙,这个相同的技巧应该适用于“ProgramFiles(x86)”。

多个反斜杠替换为正斜杠

你主要在那里:问题是,你的模式专门针对:\,但字符串中有多个\,而没有冒号。你最好的办法可能是有一个程序或函数,实际上理解Windows路径,因为它们不一定在前面有驱动器号(参见https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats)。但这个模式适用于所有反斜杠:

bash$ v='a\b\c'
bash$ echo ${v//\\/\/}
a/b/c

双斜杠表示“替换所有出现的情况”。然后 * 模式 * 是\\,它匹配一个反斜杠。下一个斜杠引入替换字符串,它是\/,这意味着一个正斜杠。(这也可以写成/,但我发现很难阅读,奇怪的是。)
当然这并不能替换C:中的冒号,所以我们需要再做一次替换,你不能在一个${...}扩展中做这件事,所以技巧是再加一个:

bash$ v='C:\a\b\c'
bash$ echo ${v//\\/\/}
C:/a/b/c
bash$ v1="${v//\\//}"; echo ${v1/:/}
C/a/b/c

把它放在一个shell函数中,你最终可以使它足够聪明,可以处理所有有效的路径,这样你就可以使用local来防止变量名v1泄漏。

kpbwa7wx

kpbwa7wx2#

关于APPDATA:cygpath程序可以在Windows、Unix和“混合”约定之间转换路径名。Cygwin和Git for Windows都附带了这个工具。示例:

$ echo "$APPDATA"
C:\Users\me\AppDataRoaming\
$ cygpath -u "$APPDATA"
/c/Users/me/AppData/Roaming
$ cygpath -m "$APPDATA"
C:/Users/me/AppData/Roaming
$ cygpath -w "$APPDATA"
C:\Users\me\AppData\Roaming

“混合”格式非常有用,因为即使是大多数Windows程序和Git for Windows也可以直接处理这种格式。
cygpath的输出赋值给一个变量的工作方式如下(注意引号!):

$ XAPP=$(cygpath "$APPDATA")
$ echo "$XAPP"
$ cd "$XAPP"
vecaoik1

vecaoik13#

你的问题几乎包含了答案。你只需要做:

printenv "ProgramFiles(x86)"

在我的机器上,这给出了输出:

C:\Program Files (x86)

如果你需要将它赋值给一个变量,你可以通过command substitution的常用方法来完成:

progfiles86="$(printenv "ProgramFiles(x86)")"

# It's possible that ProgramFiles(x86) was not set, or it was set to the
# empty string. Do this if you need to distinguish between those two cases:
if [ $? != 0 ]; then
    unset progfiles86  # because ProgramFiles(x86) was not set
fi

现在你可以根据需要操作${progfiles86}了。如果你需要在一个子进程中访问它,不要忘记使用export

如果你只是想要ProgramFiles(x86)变量的值,那么你可以停止阅读这里。

命令替换去除尾随的换行符。ProgramFiles(x86)变量不太可能包含任何换行符,因为它是一个文件路径,Windows上的文件路径不允许包含换行符,但对于FOO(BAR)这样的通用变量,可能会发生这种情况。
要保留尾随换行符,请执行以下操作:

foobar="$(printenv "FOO(BAR)" && echo /)"
foobar="${foobar%$'\n'/}"  # strip extra newline from printenv and '/' from echo

这利用了在GNU系统(包括Windows上的Git Bash)和BSD系统(包括macOS)上实现的printenv命令的一些怪癖:

  • 如果FOO(BAR)被设置为任何值,包括空字符串,那么printenv打印该值,后跟一个尾随的换行符,并正常退出。(因此,如果FOO(BAR)为空,printenv打印一个换行符。)
  • 如果未设置FOO(BAR),则printenv不打印任何内容,并以非零状态退出。

因此,如果需要区分空的FOO(BAR)和未设置的FOO(BAR)

foobar="$(printenv "FOO(BAR)" && echo /)"

if [ $? == 0 ]; then
    foobar="${foobar%$'\n'/}"  # strip extra newline from printenv and '/' from echo
else
    unset foobar  # because FOO(BAR) was not set
fi

请记住,$?只能用于访问紧接在它之前的命令的退出状态。

相关问题