locale
当我在终端中运行命令时,将打印 shell 的区域设置变量。
有没有办法获取任何其他进程(除了 shell)的区域设置变量?
答案1
Linux 上的GNU xargs
:
xargs -r0a "/proc/$pid/environ" sh -c 'exec env -i -- "$@" locale' sh
将在环境副本中运行locale
进程 pid$pid
传递给它最后执行的命令。
请注意,locale
作为外部的,它只关心环境变量,而不关心 shell 变量(如果它们尚未导出)。
即使未导出LC_*
、LANG
、变量,shell 本身的本地化设置也可能会受到影响。LANGUAGE
一些注意事项:
- 使用本地化的程序通常会进行
setlocale(LC_ALL, "")
初始化全部他们的本地化设置基于环境,但他们不必这样做。 - 他们可能会
setlocale()
使用不同的参数进行调用(不太可能)。 - 他们可能会在修改环境之前或之后调用它(使用
putenv()
/等 APIsetenv()
)。 - 这些
putenv()
/setenv()
传统上不会修改暴露的区域,/proc/$pid/environ
但 IIRC 它在最新版本的 Linux 和 GNU libc 中发生了变化。 - 不管那些
putenv()
/setenv()
,进程最终可能会修改它们暴露的堆栈区域/proc/$pid/environ
(不太可能)。
另一种选择是将 gdb 附加到进程并执行以下操作:
call system("locale")
但这是相当侵入性的。
该程序将使用进程本身准备的环境(假设它使用environ
和/或putenv()
/ setenv()
,但不是所有应用程序,尤其是 shell 都这样做)。
setlocale()
使用 gdb,您实际上还可以通过使用 NULL 第二个参数调用每个语言环境类别来直接查询本地化设置。
要了解给定类别的值:
$ printf '#include <locale.h>\nLC_COLLATE\n' | gcc -E -x c - | tail -n 1
3
要打印区域设置名称gdb
:
(gdb) p (char*)setlocale(3, 0)
$3 = 0xde8f40 "en_GB.UTF-8"
或者:
(gdb) x/s setlocale(3, 0)
0xde8f40: "en_GB.UTF-8"
答案2
即使在 shell 中,调用也locale
并不总能给出可靠的结果。
例如,Bourne Shell 将环境变量导入到本地 shell 变量中,并将导入的值转发给其子代,但同时允许修改相关的本地变量而不修改导出的值。 Bourne Shell 语言环境设置基于 shell 变量的内部值,而不是基于导入或导出的环境。
由于这适用于 LC_* 变量,因此 Bourne Shell 可以在与locale
命令报告不同的区域设置中运行。顺便说一句:您可以通过调用set -o posix
Bourne Shell 来更改此设置...告诉 Bourne Shell 将导入变量的导出值与内部值同步。
更重要的是:从 POSIX.1-2008 开始,有一种方法可以让程序同时使用多个语言环境。例如,这对于喜欢解析例如美国语言C
环境中的浮点常量的编译器来说很重要,其中不寻常的浮点分隔符“.”。使用,同时仍然根据不同的区域设置给出警告和其他输出。
同样的方法也经常用于让线程程序对不同的线程使用不同的区域设置。
正如您所看到的,查看其他程序的环境只能粗略地了解区域设置可能是什么,但永远不会返回真实的授予结果。