Linux 为什么不';每次运行命令时,位置变量都会发生变化

Linux 为什么不';每次运行命令时,位置变量都会发生变化,linux,bash,shell,sh,Linux,Bash,Shell,Sh,我正在学习shell脚本,我遇到了这种情况 我们说位置变量是环境变量,但为什么它们不会在每次执行命令时都改变呢 看看这个 set v1set v2set v3set v4set old=$# #Just a random command ls -l new=$# echo $old $new 它输出4。如果环境变量是全局的,为什么不像我运行的那样,它不是41,它应该有更新的位置变量?我认为$#不适用于交互式shell。它在脚本中运行良好。试试这个 $ cat try.sh #!/bin/

我正在学习shell脚本,我遇到了这种情况

我们说位置变量是环境变量,但为什么它们不会在每次执行命令时都改变呢

看看这个

set v1set v2set v3set v4set
old=$#

#Just a random command
ls -l

new=$#

echo $old $new
它输出
4
。如果环境变量是全局的,为什么不像我运行的那样,它不是
41
,它应该有更新的位置变量?

我认为
$#
不适用于交互式shell。它在脚本中运行良好。试试这个

$ cat try.sh
#!/bin/bash
echo $*
echo $#

$ ./try.sh one
one
1

$ ./try.sh one two
one two
2

$ ./try.sh one two three
one two three
3
我认为
$#
不适用于交互式shell。它在脚本中运行良好。试试这个

$ cat try.sh
#!/bin/bash
echo $*
echo $#

$ ./try.sh one
one
1

$ ./try.sh one two
one two
2

$ ./try.sh one two three
one two three
3
如果环境变量是全球性的,为什么不是4 1

我假定您正在询问为什么运行命令
ls-l
不会将位置参数从四个更改为一个,其中一个是
-l

对于程序
ls
,它会将它们设置为
-l
。当程序
ls
查询其位置参数时,它被告知is有一个由
-l
组成的参数。但是,一旦
ls
终止,位置参数将返回到以前的状态

如果环境变量是全球性的

即使对于全局环境变量,在子进程中对它们的更改也不会出现在父进程中。环境变量的交流是单向的:只从父母到孩子

例如:

$ cat test1.sh
echo "in $0, before, we have $# pos. params with values=$*"
bash test2.sh calling test2 from test1
echo "in $0, after , we have $# pos. params with values=$*"

$ cat test2.sh
echo "in $0, we have $# pos. params with values=$*"

$ bash test1.sh -l
in test1.sh, before, we have 1 pos. params with values=-l
in test2.sh, we have 4 pos. params with values=calling test2 from test1
in test1.sh, after , we have 1 pos. params with values=-l
另一个例子显示,子对象对环境变量的更改不会影响父对象:

$ cat test3.sh
export myvar=1
echo "in $0, before, myvar=$myvar"
bash test4.sh
echo "in $0, after,  myvar=$myvar"

$ cat test4.sh
export myvar=2
echo "in $0, myvar=$myvar"

$ bash test3.sh
in test3.sh, before, myvar=1
in test4.sh, myvar=2
in test3.sh, after,  myvar=1
如果环境变量是全球性的,为什么不是4 1

我假定您正在询问为什么运行命令
ls-l
不会将位置参数从四个更改为一个,其中一个是
-l

对于程序
ls
,它会将它们设置为
-l
。当程序
ls
查询其位置参数时,它被告知is有一个由
-l
组成的参数。但是,一旦
ls
终止,位置参数将返回到以前的状态

如果环境变量是全球性的

即使对于全局环境变量,在子进程中对它们的更改也不会出现在父进程中。环境变量的交流是单向的:只从父母到孩子

例如:

$ cat test1.sh
echo "in $0, before, we have $# pos. params with values=$*"
bash test2.sh calling test2 from test1
echo "in $0, after , we have $# pos. params with values=$*"

$ cat test2.sh
echo "in $0, we have $# pos. params with values=$*"

$ bash test1.sh -l
in test1.sh, before, we have 1 pos. params with values=-l
in test2.sh, we have 4 pos. params with values=calling test2 from test1
in test1.sh, after , we have 1 pos. params with values=-l
另一个例子显示,子对象对环境变量的更改不会影响父对象:

$ cat test3.sh
export myvar=1
echo "in $0, before, myvar=$myvar"
bash test4.sh
echo "in $0, after,  myvar=$myvar"

$ cat test4.sh
export myvar=2
echo "in $0, myvar=$myvar"

$ bash test3.sh
in test3.sh, before, myvar=1
in test4.sh, myvar=2
in test3.sh, after,  myvar=1

有趣的问题-你说得对

为了理解它,您需要了解运行任何命令时会发生什么,如
ls-l
。它与“恢复变量或类似变量”无关

当您要运行任何命令时

  • bash
    将自身分叉为两个相同的副本
  • 一个副本(称为子副本)将用所需的命令(例如,用
    ls-l
    )替换自身
  • 此时,子进程将获得位置变量的正确计数
  • 记住——这种情况发生在子进程中,第二个(父)进程对此一无所知
  • 父对象只需等待子对象完成(当然,他的
    $#
    不会更改,因为对于父对象,什么都不会发生,只会等待)
  • 当孩子(
    ls-l
    )完成时,家长继续运行-当然,他的
    $#
    没有理由改变

  • ps:上面的问题很简单。事实上,在fork之后,它们不是完全相同的,而是在一个数字上有所不同-父进程得到子进程的编号,这个编号的子进程有“0”

    有趣的问题-你得到了一个很好的答案

    为了理解它,您需要了解当您运行任何命令时会发生什么,比如
    ls-l
    。它与“变量被还原或类似”无关

    当您要运行任何命令时

  • bash
    将自身分叉为两个相同的副本
  • 一个副本(称为子副本)将用所需的命令(例如,用
    ls-l
    )替换自身
  • 此时,子进程将获得位置变量的正确计数
  • 记住——这种情况发生在子进程中,第二个(父)进程对此一无所知
  • 父对象只需等待子对象完成(当然,他的
    $#
    不会更改,因为对于父对象,什么都不会发生,只会等待)
  • 当孩子(
    ls-l
    )完成时,家长继续运行-当然,他的
    $#
    没有理由改变

  • ps:上面的内容很简单。事实上,在fork之后,它们不是完全相同的,而是在一个数字上有所不同-父进程获得子进程的编号,该编号的子进程为“0”

    你所说的“位置变量是环境变量”是什么意思?当您运行类似于
    ls-l
    的命令时,无论在该命令执行过程中发生了什么(即使它涉及调用一个子shell,但在本例中并不涉及)不会影响当前shell中的环境。@Nate,请不要将人们指向ABS;irc.freenode.org#bash在帮助人们摆脱他们从中养成的坏习惯方面有足够的困难。对于避免演示代码中的坏习惯,它的维护更加谨慎。@charlesduff:足够公平:我刚刚抓到了我在Google上找到的第一个讨论子shell中变量作用域的链接。我已经删除了我发布的链接,因此人们将使用你的链接。shell中的位置参数是传递给它的参数(或通过使用
    set
    builtin)的结果。它们不是在invo之前设置的