可以在 Cygwin 或 Git Bash 中访问 Windows %PROGRAMFILES(X86)% 环境变量吗?

可以在 Cygwin 或 Git Bash 中访问 Windows %PROGRAMFILES(X86)% 环境变量吗?

在 Git Bash 和 Cygwin 中,我可以轻松访问 Windows%PROGRAMFILES%环境变量:

$ echo $PROGRAMFILES
C:\Program Files

$ echo ${PROGRAMFILES}
C:\Program Files

但是,由于变量名中有括号,我无法%PROGRAMFILES(X86)%以相同的方式访问:

$ echo $PROGRAMFILES(X86)
bash: syntax error near unexpected token `('

$ echo ${PROGRAMFILES(X86)}
bash: ${PROGRAMFILES(X86)}: bad substitution

$ echo ${PROGRAMFILES\(X86\)}
bash: ${PROGRAMFILES\(X86\)}: bad substitution

当然,除非我使用命令提示符:

C:\Users\myname>echo %PROGRAMFILES(X86)%
C:\Program Files (x86)

(我很少这样做!)

有没有办法转义环境变量名中的括号,或者这些括号在类似 Bash 的环境中完全无效(因此无法访问)?

答案1

更好的答案

事实证明,cygpath -F我们可以查询一些特殊的“文件夹 ID”。下面将输出 ID 以及系统的值。

for ((id=0;id<=64;id++))
do
  F=$(cygpath -amF $id 2> /dev/null)
  [[ -n "$F" ]] && echo "$id = $F"
done

作为一行代码:

for ((id=0;id<=64;id++)); do F=$(cygpath -amF $id 2> /dev/null); [[ -n "$F" ]] && echo "$id = $F"; done

同时我检查了代码。函数get_special_folder()使用cygpath.ccSHGetSpecialFolderLocation()随后SHGetPathFromIDListW,因此值 42(十六进制 0x2a)对应于CSIDL_PROGRAM_FILESX86,因此只要 Windows 支持其 API 契约,我们就可以依赖它。

重要的:“混合表示”(cygpath -m) - 本质上是用正斜杠代替反斜杠的 Windows 路径 - 似乎在包括 MSYS2 在内的 Cygwin 版本中更加健壮和可移植!


原始答案

这是一个适用于 Windows 的 Git 和 Cygwin 的 Bash 的解决方案(也适用于 MinGW):

PF86="$(cygpath -u "$(env|tr -d '\r'|gawk -F= '$1 == "ProgramFiles(x86)" {print $2}')")"

其余部分是利用填充的环境变量。建议检查输出是否为空并采取相应措施。示例:

PF86="$(cygpath -u "$(env|tr -d '\r'|gawk -F= '$1 == "ProgramFiles(x86)" {print $2}')")"
[[ -n "$PF86" ]] || { echo "\${ProgramFiles(x86)} not set"; exit 1; }

笔记: gawk通常可以用 代替awk。取决于您的 AWK 脚本的具体细节,但这个非常简单,它应该适用于大多数(如果不是全部) AWK 版本。

它有什么作用?

  1. env以成对的形式列出环境变量key=value,每行一个
  2. tr -d '\r'从 stdin 中删除所有回车符,并将结果写入 stdout
  3. gawk -F= '$1 == "ProgramFiles(x86)" {print $2}')"用作=字段分隔符,并在第一个字段中匹配ProgramFiles(x86)。匹配后,它会打印字段 2(值)。
  4. 然后将上述所有步骤的输出用作输入cygpath -u,将路径从 Windows 转换为 Unix 表示

请注意,存在一个非常微妙的差异,这会导致\r(回车符)保留为从 Windows 程序捕获的输出值的一部分。对于上述情况,这tr -d '\r'可能不是绝对必要的,但我宁愿安全而不要后悔。

免责声明:虽然从严格意义上来说,这可能不算“漂亮”,但事实证明,这是解决当前问题的非常可靠的方法。我在许多脚本中都使用过它,也用于专业用途。我使用过的一个应用程序是vswhere.exe,其众所周知的路径基于此子文件夹。这也是解决方法vswhere的起源之一tr -d '\r'

注意:我没有改变上面的原始答案,但强烈建议使用“混合表示”(cygpath -m),而不是“通用 Unix 表示”(我编造的;cygpath -U)!

答案2

我只是对字符串进行了硬编码。我知道这不是一般情况,但为了方便复制粘贴,我将这个字符串和所有转义字符放在了这里:

/cygdrive/c/Program\ Files\ \(x86\)/

答案3

在 C 级别上,环境变量名称可以包含来自posix 可移植字符集,除了 NUL。

在 bash 中,多变的只能包含某些字符(例如,不能包含括号),并且环境变量在 bash 中只是一个普通变量,恰好被导出。

由于大多数 shell 对环境变量的命名都有这样的限制,您无法设置名为的变量PROGRAMFILES(X86),并且如果您使用一种可以对环境执行 Posix 允许的所有操作的语言编写自己的程序(例如,您用 C 或 Ruby 编写),创建具有这样名称的变量并不是很明智。

如果你遇到这种情况,你的 bash 脚本的恶意父进程确实创建了一个具有如此奇怪名称的变量,你可以取回在 shell 中使用以下命令获取此变量的值printenv

value=$(printenv 'PROGRAMFILES(X86)')

相关内容