变量是 $0 和 $1 外壳/环境变量吗?

use*_*202 17 shell

还有在shell变量一样$0$1$2$?,等。

我尝试使用以下命令打印 shell 和环境变量:

set
Run Code Online (Sandbox Code Playgroud)

但是这些变量不在列表中。

所以基本上这些变量不被认为是shell/环境变量,对吧?(即使要输出它们,您也必须在它们前面加上$,就像使用 shell/环境变量一样)

che*_*ner 25

变量是 shell 中三种不同的参数之一。

  1. 变量是一个参数,其名称是有效的壳标识符; 以_或 一个字母开头,后跟零个或多个字母、数字或_
  2. 位置参数编号参数$1$2...
  3. 特殊参数都有单字符的名称,除了$0,他们都是不同的标点字符。

set 只显示 shell 的变量。

shell 变量的一个子集是环境变量,它们的值要么是在 shell 启动时从环境继承的,要么是通过将export属性设置为有效名称而创建的。

  • 请注意,`set` 显示了`zsh` 中的所有参数(不是$1、$2...而是$*、$@)以及bash 和bosh 中的函数。一些 shell,如 ksh93 和未映射到 shell 变量的破折号输出环境变量的旧版本。(`env 1=foo ksh -c set` 会打印 `1=foo`) (2认同)

Ser*_*nyy 11

环境变量与位置参数

在我们开始讨论$INTEGER变量的类型之前,我们需要了解它们的真正含义以及它们与环境变量的区别。诸如此类的变量$INTEGER称为位置参数。这在 POSIX(便携式操作系统接口)标准的2.1 节(重点是我的)中有描述:

  1. shell 执行一个函数(请参阅函数定义命令)、内置(请参阅特殊内置实用程序)、可执行文件或脚本,将参数的名称作为编号为 1 到 n 的位置参数,以及命令的名称(或在脚本中的函数的情况下,脚本的名称)作为编号为 0 的位置参数(请参阅命令搜索和执行)。

相比之下,诸如$HOME和 之$PATH类的变量是环境变量。它们的定义在标准的第 8 节中描述:

本章中定义的环境变量会影响多个实用程序、函数和应用程序的运行。还有其他环境变量只对特定实用程序感兴趣。仅适用于单个实用程序的环境变量被定义为实用程序描述的一部分。

注意他们的描述。位置参数旨在出现在命令的前面,即command positional_arg_1 positional_arg_2.... 它们旨在由用户提供以告诉命令具体做什么。当你这样做时echo 'Hello' 'World',它会打印出HelloWorld字符串,因为这些是echo你想要echo操作的东西的位置参数。并且echo构建为将位置参数理解为要打印的字符串(除非它们是像 那样的可选标志之一-n)。如果你用不同的命令来做这件事,它可能不明白什么HelloWorld是因为它可能需要一个数字。请注意,位置参数不是“继承的”——除非明确地传递给子进程,否则子进程不知道父进程的位置参数。通常,您会看到使用包装器脚本传递位置参数 - 这些脚本可能会检查命令的现有实例或向将被调用的实际命令添加额外的位置参数。

相比之下,环境变量旨在影响多个程序。它们是环境变量,因为它们是在程序本身之外设置的(更多内容见下文)。某些环境变量,例如HOMEPATH具有特定的格式,特定的含义,并且它们对每个程序都具有相同的含义。HOME变量对于外部实用程序/usr/bin/find或您的 shell(因此对于脚本)的含义相同- 它是进程运行的用户名的主目录。请注意,环境变量可用于解释特定的命令行为,例如UID环境变量可用于检查脚本是否以 root 权限运行,并相应地分支到特定操作。环境变量是可继承的 - 子进程获得父环境的副本。另请参阅如果进程继承了父级的环境,为什么我们需要导出?

简而言之,主要区别在于环境变量是在命令之外设置的,并不意味着要改变(通常),而位置参数是指要由命令处理并且它们会改变的东西。


不仅仅是外壳概念

我从评论中注意到您正在混淆终端和外壳,并且真的建议您阅读有关曾经是物理设备的真实终端的信息。如今,我们通常所指的“终端”,黑色背景和绿色文本的窗口实际上是软件,是一个进程。终端是一个运行 shell 的程序,而 shell 也是一个程序,但它会读取您输入的内容以执行(也就是说,如果它是交互式 shell;非交互式 shell 是脚本和sh -c 'echo foo'调用类型)。更多关于贝壳在这里

这是一个重要的区别,但同样重要的是要认识到终端是一个程序,因此遵守相同的环境和位置参数规则。您的gnome-terminal启动时间将查看您的SHELL环境变量,并为您生成适当的默认 shell,除非您使用-e. 假设我将默认 shell 更改为ksh - gnome-terminal 然后将生成ksh而不是bash. 这也是程序如何使用环境的一个例子。如果我明确告诉gnome-terminalwith-e运行特定的 shell - 它会这样做,但它不会是永久性的。相比之下,环境基本上是不变的(稍后会详细介绍)。

如您所见,环境变量和位置变量都是进程/命令的属性,而不仅仅是 shell。谈到shell脚本,它们也遵循C编程语言设定的模型。以 Cmain函数为例,它通常看起来像

int main(int argc, char **argv)
Run Code Online (Sandbox Code Playgroud)

,其中 argc是命令行参数的数量,并且argv是有效的命令行参数数组,然后有environ函数(在 Linux 上是man -e 7 environ)来访问诸如用户主目录路径、PATH我们可以在其中查找可执行文件的目录列表等内容。 Shell 脚本也以类似的方式建模。在 shell 术语中,我们有位置参数$1$2等等,而$#是位置参数的数量。怎么样$0?那是可执行文件本身的名称,它也是从 C 编程语言建模的 -argv[0]将是您的 C“可执行文件”的名称。这对于大多数编程和脚本语言来说都是正确的

交互式与非交互式 shell

我已经暗示过的一件事是交互式和非交互式 shell之间的区别。您输入命令的提示 - 这是交互式的,它与用户进行交互。相比之下,当你有一个 shell 脚本或者你运行bash -c''的是非交互式的。

这就是区分变得重要的地方。您运行的 shell 已经是一个进程,它是用位置参数生成的(对于bash登录 shell 是一个“......其参数零的第一个字符是 -,或者一个以 --login 选项开头的字符。”(参考) )

相比之下,使用-coption启动的脚本和 shell可以利用$1$2参数。例如,

$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
  File: '/etc/passwd'
  Size: 2913        Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d  Inode: 6035604     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
 Birth: -
Run Code Online (Sandbox Code Playgroud)

请注意,我也在sh那里使用过,因为-c选项的小怪癖是采用第一个位置参数并将其分配给$0,这与通常的程序名称不同。

需要注意的另一件事是位置参数是我所说的“可框架”。请注意,我们首先bash使用自己的位置参数启动,但是这些位置参数变成了echo和 的参数stat。每个程序都以自己的方式理解它。如果我们给stat一个字符串Hello World并且没有文件,Hello World它会产生一个错误;bash将其视为一个简单的字符串,但stat希望该字符串是现有文件名。相比之下,所有程序都会同意环境变量HOME是一个目录(除非程序员以不合理的方式对其进行编码)。


我们可以搞乱环境变量和位置参数吗?

从技术上讲,我们可以同时处理这两种情况,但我们不应该处理环境变量,因为我们通常必须提供位置参数。我们可以在 shell 中运行命令并预先添加一个变量,例如:

$ hello=world bash -c 'echo $hello'
world
Run Code Online (Sandbox Code Playgroud)

我们还可以export variable=value在 shell 或脚本中使用from将变量放入环境中。或者我们可以使用env -c command arg1 arg2. 但是,通常不建议搞乱环境,尤其是使用大写变量或覆盖已经存在的环境变量。请注意,这是推荐的,但不是标准。

对于位置参数,设置它们的方法很明显,只需将它们添加到命令中,但也有其他方式设置它们,以及通过shift命令更改这些参数的列表。

总之,这两者的目的是不同的,它们存在是有原因的。我希望人们从这个答案中获得一些见解,就像我写这个答案一样,阅读它很有趣。


设置命令的注意事项

set根据手册,该命令的行为如下(来自 bash 手册,强调已添加):

如果没有选项,每个shell 变量的名称和值将以一种格式显示,该格式可以重复用作设置或重置当前设置的变量的输入。

换句话说,set查看特定于 shell 的变量,其中一些恰好在环境中,例如HOME. 相比之下,像envprintenv查看命令运行的实际环境变量的命令。另请参见


jes*_*e_b 5

这些$1, $2, $3, ..., ${10}, ${11}变量称为位置参数,在 bash 手册部分有介绍3.4.1

3.4.1 位置参数

位置参数是由一位或多位数字表示的参数,而不是单个数字 0。位置参数是在调用时从 shell 的参数分配的,并且可以使用 set 内置命令重新分配。位置参数 N 可以引用为 ${N},或者当 N 由单个数字组成时引用为 $N。位置参数不能用赋值语句赋值。set 和 shift 内置函数用于设置和取消设置它们(请参阅 Shell 内置命令)。执行 shell 函数时,位置参数会被临时替换(请参阅 Shell 函数)。

当扩展包含多个数字的位置参数时,必须将其括在大括号中。

至于$?and $0,这些特殊参数将在下一节中介绍3.4.2

3.4.2 特殊参数

shell 对几个参数进行了特殊处理。这些参数只能被引用;不允许分配给他们。

...

?

($?) 扩展到最近执行的前台管道的退出状态。

0

($0) 扩展到 shell 或 shell 脚本的名称。这是在 shell 初始化时设置的。如果使用命令文件调用 Bash(请参阅 Shell 脚本),则 $0 设置为该文件的名称。如果 Bash 使用 -c 选项启动(请参阅调用 Bash),则 $0 将设置为要执行的字符串之后的第一个参数(如果存在)。否则,它被设置为用于调用 Bash 的文件名,由参数零给出。


Sté*_*las 5

$1, $2... 是位置参数,它们不是变量,更不是环境变量。

在类似Bourne壳术语,$something被称为参数膨胀(也盖${something#pattern}和更多的像一些壳${array[x]}${param:offset}${x:|y}和许多更多的扩展运算符)。

有不同种类的参数:

  • 变量一样$foo$PATH
  • 位置参数 ( $1, $2... 你的脚本收到的参数)
  • 其他特殊参数,如$0, $-, $#, $*, $@, $$, $!, $?...

Bourne 之类的 shell 中的变量名称必须以一个字母字符开头(任何被语言环境识别的字符,或根据 shell 限制为 a-zA-Z)和下划线,然后是零个或多个字母数字字符或下划线。

根据 shell,变量可以有不同的类型(标量、数组、散列)或给定某些属性(只读、导出、小写...)。

其中一些变量是由 shell 创建的,或者对 shell 具有特殊含义(如$OPTIND, $IFS, $_...)

具有export属性的Shell 变量会作为环境变量自动导出到 Shell 执行的命令中。

环境变量是一个独立于 shell 变量的概念。导出 shell 变量并不是将环境变量传递给命令执行的唯一方法。

VAR=foo
export VAR
printenv VAR
Run Code Online (Sandbox Code Playgroud)

将一个VAR环境变量传递给printenv命令(我们告诉它打印其内容),但您也可以这样做:

env VAR=foo printenv VAR
Run Code Online (Sandbox Code Playgroud)

或者:

perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'
Run Code Online (Sandbox Code Playgroud)

例如。

环境变量可以有任何名称(可以包含任何字符,但=甚至可以为空)。为环境变量提供一个与类似 Bourne 的 shell 变量名称不兼容的名称并不是一个好主意,但它是可能的:

$ env '#+%=whatever' printenv '#+%'
whatever
Run Code Online (Sandbox Code Playgroud)

Shell 会将它们接收到的环境变量映射到仅适用于名称为有效 shell 变量的那些环境变量的 shell 变量(并且在某些 shell 中会忽略一些特殊的,例如$IFS)。

因此,虽然您可以将1环境变量传递给命令:

$ env '1=whatever' printenv 1
whatever
Run Code Online (Sandbox Code Playgroud)

这并不意味着使用该环境变量调用 shell 会设置$1参数的值:

$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo
Run Code Online (Sandbox Code Playgroud)


Jar*_*era 3

不,这些是脚本的参数。例如,如果您像这样调用脚本:

mynicescript.sh one two three
Run Code Online (Sandbox Code Playgroud)

然后在脚本中,这些参数将可用为

$1 = one
$2 = two
$3 = three
Run Code Online (Sandbox Code Playgroud)

$0 是脚本本身的名称。

因此,当您在脚本之外时,这些变量不可用($0 除外,它显示 /bin/bash - shell 本身)。

  • @user7681202:您可以在终端中看到哪些?`$0` 将指向当前的终端进程(可能是 bash),而 `$?` 只是最后一个进程的退出代码。 (2认同)

归档时间:

查看次数:

6736 次

最近记录:

6 年,9 月 前