繁体   English   中英

在后台外壳中分配变量

[英]Assign variable in the background shell

我想要在显示这样的进度指示器时在后台分配变量

sleep_echo(){
  sleep $1
  echo $2
}
show_ellapsed_time () {
  #...
}

(mivar=$(sleep_echo 3 hello)) &
show_ellapsed_time $!
echo $mivar
echo "after asignment"

当我在终端中运行它时它会输出进度指示器,然后myvar

processing 00:00:03 [\]
hello
after asignment

但是,当我在脚本中运行分配时,分配不会发生

processing 00:00:03 [\]

after asignment

为什么会失败? 函数不被调用吗?

子进程无法通过变量分配与其父进程进行通信。

在Bash中,可以通过几种方式创建子进程:

  • 启动外部命令
  • 通过用()括起来的语句启动子外壳
  • 使用重定向(例如管道)时启动子外壳
  • 使用&在后台启动任何东西

外部命令会收到所有标记为导出的shell变量的副本(例如export VARlocal -x VAR

子shell接收所有变量的副本。 这很有用,但是很容易就不会意识到自己处在新的环境中。 在子进程中所做的任何分配都不会被父进程看到。

你可以做什么:

  • 使用进程间通信来捕获输出
  • 将所需的信息放入文件中,因为所有进程都可以访问文件(假设有足够的权限)
  • 使用命名的FIFO,这是一种特殊的文件,允许单独的进程进行通信(请参阅mkfifo )。
  • 通过使用正确的构造方式来构建管道,从而以一种方式构造脚本,从而将最需要的代码块保留在主上下文中。

对于最后一个,使用<(COMMAND)>(COMMAND)类的进程替换通常比使用|构建的典型管道要好得多| ,例如,允许while循环的主体(或实际上是向/从中馈入替代的任何其他语句)保留在脚本的上下文中。 这允许循环内的变量分配具有预期的效果。

就您而言,您有以下几行:

(mivar=$(sleep_echo 3 hello)) &
show_ellapsed_time $!

也许您可以将它们替换为:

show_ellapsed_time &
BG_PID=$!
mivar=$(sleep_echo 3 hello)
kill $BG_PID

我对您的show_ellapsed_time了解,如果没有传递给该函数的参数,那是否可以正常工作,但是分配可以工作。 您还可以将主外壳的PID传递给函数,如下所示:

show_ellapsed_time $$ &

您的变量在另一个作用域内。 如果将某些命令用圆括号()括起来,则在该范围外使用的变量将不再可访问。 一个例子:

(myvar=test)
echo "myvar=$myvar"

会给:

myvar=

因为不再知道myvar。 您的命令似乎在终端中起作用的唯一原因是: 可能是您在测试期间设置了变量mivar 因此该变量仍处于设置状态。 如果您打开一个新终端,您的脚本将不再起作用。

将流程发送到后台(使用& ); 也将导致范围发生变化; 因此即使卸下支架也无济于事。 我认为您应该重新设计脚本(或考虑使用高级语言),因为似乎您想将多线程引入bash :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM