使用 `_` 作为传递给命令的环境变量

使用 `_` 作为传递给命令的环境变量

来自 bash 手册

_

在 shell 启动时,设置为用于调用在环境或参数列表中传递的 shell 或正在执行的 shell 脚本的绝对路径名。随后,在扩展后扩展至上一个命令的最后一个参数。还设置为用于调用执行的每个命令并放置在导出到该命令的环境中的完整路径名。检查邮件时,该参数保存邮件文件的名称。

对于粗体字,斯蒂芬说

bash 与其他一些 shell 一样,会将_环境变量传递给它执行的命令,其中包含 bash 用作系统调用的第一个参数的路径execve()

$ env | grep '^_'
_=/usr/bin/env

如何获取_任意命令的环境变量值而不是env,以验证其值是否是该命令的可执行文件或脚本的路径名?

谢谢。

答案1

$_值对子进程可见。你如何让孩子读懂它取决于你使用的语言。

例如在C语言中

#include <stdlib.h>
#include <stdio.h>

main()
{
  char *x=getenv("_");
  printf("%s\n",x);
}

然而,程序不能依赖于$_被设置,因为其他 shell 可能会做不同的事情。

例如

$ env -i /bin/bash -c ./a.out
./a.out

$ env -i /bin/ksh -c ./a.out 
*31801*./a.out

$ env -i /bin/sh -c ./a.out 
Segmentation fault (core dumped)

/bin/sh(在这个 Ubuntu 系统上是“dash”)根本没有设置 $_,所以这个简单的程序崩溃了。哎呀:-)

$_您的调用程序根本看不到这个值。事实上,在调用 shell 中$_设置为上一行的最后一个参数

$ ls /tmp > /dev/null
$ echo $_
/tmp

$ echo hello
hello
$ echo $_
hello

答案2

如果您在基于 Linux 的系统上运行,则可以通过读取伪文件来检查进程的环境/proc/[pid]/environ- 但前提是该进程仍在运行并且您拥有权限。

env其内容与 或 的输出类似,printenv只是变量由空字符而不是换行符分隔。

man proc并搜索environ更多信息。

例如:

$ /bin/sleep 60 &
[1] 25909
$ tr '\0' '\n' < /proc/$!/environ | grep '^_='
_=/bin/sleep
$ 

其中$!扩展为最近放入后台的作业的 PID。

对于快速完成的程序来说,这将更加困难。

如果您的环境变量的值包含 ,则可能会产生误报,"\n_="因为它无法区分属于环境一部分的换行符和从空字符翻译的换行符。这不太可能是一个问题,但如果是的话,你需要做一些不同的事情:

perl -nE 'undef $/; say grep /^_=/, split /\0/, scalar <>' /proc/$!/environ

答案3

这是不可能的(在正在运行的 shell 中)。

要打印环境变量值,您需要一个命令,可以使用printenv

$ printenv "LANG"
LANG=en_US.UTF-8

它将报告导出到命令环境的变量值。或者,您将在当前运行的 shell 中使用 echo(或 printf 或 print)变量的值:

$ echo "$LANG"
LANG=en_US.UTF-8

在这两种情况下,命令都已执行,并且变量的值$_将设置为所执行命令的最后一个参数(如果有任何命令被执行)。

$ ls
$ echo ".$_."
.--color=auto.
$ echo ".$_."
..--color=auto..
$ echo ".$_."
...--color=auto...

$ bash -c 'echo $_'
/bin/bash

$ bash -c 'ls -l >>/dev/null; echo $_'
-l

因此:执行的任何命令都将为执行该命令的子 shell 设置并由同一 shell$_打印为 的值。$_

有些 shell 不使用或设置 tempal $_

$ dash -c 'ls -l >/dev/null; echo ".$_."'
./bin/dash.

但这只会揭示通往 的道路的价值dash。 ..

相关内容