在后台shell中分配变量

时间:2017-01-23 11:48:22

标签: bash shell

我想在后台分配变量,而我正在显示像这样的进度指示器

<div class="notifyjs-wrapper notifyjs-hidable">
     <div class="notifyjs-arrow" style="left: 41px; top: 6px; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-right: 5px solid rgb(238, 211, 215); display: none;">
     </div>
     <div class="notifyjs-container" style="left: 46px; top: -7.5px; display: none;">
         <div class="notifyjs-bootstrap-base notifyjs-bootstrap-error">
                <span data-notify-text="">test note</span>
         </div>
     </div>
</div>

当我在终端中运行时,它会输出进度指示器,然后回显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

为什么会失败?是不是调用了te函数?

2 个答案:

答案 0 :(得分:5)

子进程无法通过变量赋值与其父进程通信。

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

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

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

子壳接收所有变量的副本。这很有用,但很容易意识到你处于一个新的环境中。在子进程中进行的任何分配都不会被父母看到。

你能做什么:

  • 使用进程间通信来捕获输出
  • 将所需信息放在文件中,因为所有进程都可以访问文件(假设有足够的权限)
  • 使用命名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知道如果没有你传递给该函数的参数,它是否可以工作,但是赋值可以工作。您还可以将主shell的PID传递给函数,如下所示:

show_ellapsed_time $$ &

答案 1 :(得分:1)

你的变量在另一个范围内。如果用括号()括起一些命令,则在该范围之外不再可以访问在该范围内使用的变量。一个例子:

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

会给:

myvar=

因为myvar不再为人所知。你的命令似乎在终端中工作的唯一原因;可能是你在测试期间设置了变量mivar;所以变量仍然设置。如果您打开一个新终端,您的脚本将不再起作用。

将流程发送到后台(使用&);也会导致范围发生变化;所以即使删除括号也无济于事。我认为你应该重新设计你的脚本(或考虑使用更高级别的语言),因为你似乎想要将多线程引入bash:)