为什么 Bash 中的 echo 会修改自变量的内容?

为什么 Bash 中的 echo 会修改自变量的内容?

我有以下代码(最小示例)。

#!/bin/bash                                                                                              
                                                                                                         
echo -ne "# Foo Bar Baz Hello World \r                           "                                       
var=''                                                                                                   
                                                                                                         
function fun {
  # some stuff happening in between                                                                                         
  var='something else'
}

fun

echo $var

令人惊讶的是,输出是:

$ /tmp/test.sh
                           something else 

有人能解释一下为什么上面的 echo 能够修改变量的内容吗?

答案1

echo上面脚本中的内容是不是修改变量var。这不可以。这里发生了什么:

  1. 第一个echo被调用,打印一行"# Foo Bar Baz Hello World \r"并立即用后面的字符\r(此处:空格)覆盖它。
  2. var被设定为''
  3. 函数fun已创建。
  4. fun被调用,var被设置为'something else'
  5. 现在到了关键点:因为echo -n不打印换行符,所以 的输出会覆盖上面尾随字符之后的字符,直到达到 的var长度。var

由于这种行为,输入 ( "# Foo Bar Baz Hello World"" "和) 的所有三个部分的内容'something else'相互重叠,从而导致整个混乱。

这种纠缠的输出由脚本“传递”(并可能导致令人讨厌的副作用)。

为了更清楚地说明:

#!/bin/bash

echo -ne "# Foo Bar Baz Hello World             \r  ANYTHING"
var=''

function fun {
  var=D
}

fun

echo $var

输出:

$ /tmp/test.sh
  ANYTHINGDaz Hello World    

因此,我们了解到以下内容:

echo -ne "Something \r"echo如果后面只有空格并且脚本输出被修剪,则可以与返回值结合使用\r,但前提是前面的字符串\r长度小于var

=> 避免。

答案2

如果操作员真的想知道为什么函数可以修改主程序中的变量,那么这与作用域有关。默认情况下,所有变量的作用域都是全局的,并且可以在函数内和函数外写入和读取。换句话说,函数在与调用程序相同的 shell 中执行,而不是在子 shell 中执行。

但是,变量可以声明为函数的本地变量,在这种情况下,它们仅在创建它们的函数(及其调用的任何函数)中可见,并在退出时被销毁。

创建子 shell 时,变量将放置在环境中,并且不能在子 shell 内更改。如果它们被覆盖,那么是通过在该子 shell 中创建一个变量来覆盖的,该变量在退出时会丢失。

考虑:

#!/bin/bash                                                                                              

var=''                                                                                                   
var2=''                                                                                                   
echo ">$var<>$var2<"
                                                                                                         
function fun {
  # some stuff happening in between                                                                                         
  var='something else'
  local var2='local'
}

fun
echo ">$var<>$var2<"

(
  echo ">$var<"
  var='level'
  echo ">$var<"
)
echo ">$var<"

首先创建两个变量,看看它们是什么。接下来创建函数并将“其他内容”分配给全局变量,并创建一个包含“local”的局部变量。调用该函数。现在看一下变量,全局的已经设置了,但是本地的还没有。

作为对比,最后一部分首先从环境中回显变量,设置它并回显它。然而,从子 shell 返回时,更改会丢失:

$ ./X
><><
>something else<><
>something else<
>level<
>something else<

相关内容