后台进程似乎挂起

时间:2015-04-14 02:41:42

标签: bash shell background-process jobs fifo

编者注:OP最终希望打包来自this answer的代码 作为一个脚本。所述代码创建一个保持打开的FIFO,后台命令从中读取要处理的数据。

如果我在终端中键入它,它会起作用,但如果我在脚本文件中输入这些命令并运行它,它就不会工作。

 #!/bin/bash
 cat >a&
 pid=$!

程序似乎停留在cat>a&

运行脚本后,

$pid没有任何价值,但cat进程似乎存在。

3 个答案:

答案 0 :(得分:2)

cat >a“挂起”的原因是因为它从标准输入流(stdin,文件描述符为零)读取,默认为键盘。

添加&会导致它在后台运行,后者会与键盘断开连接。通常,这会在后台留下暂停的作业,但是,自从退出脚本后,其后台任务将被终止(发送一个SIGHUP信号)。

编辑:虽然我按照问题中的链接进行了操作,但最初并未说明OP在该阶段实际上使用了FIFO。谢谢@ mklement0。

我不明白你在这里要做什么,但我怀疑你需要将它作为“源”文件运行,如下所示:

. gash.sh

其中gash.sh是您脚本的名称。请注意前面的.

答案 1 :(得分:2)

cdarke's answer 包含关键指针您的脚本不得在进程中运行,因此您必须来源

根据您链接的问题,听起来您正在尝试执行以下操作:

  • 打开FIFO(命名管道)。
  • 无限期地保持FIFO开启。
  • 每当向其发送新数据时,从该FIFO读取后台命令。

请参阅底部了解可行的解决方案。

关于症状的解释

  • 运行脚本未来源(不包含.)表示脚本子流程中运行 ,具有以下含义:

    • 脚本中定义的变量仅在该脚本中可见,并且当脚本完成运行时,变量将完全不存在。
      • 这就是为什么在运行脚本后没有看到脚本的$myPid变量的原因。
    • 当脚本完成运行时,其后台任务(cat >a&)被终止(正如cdarke所解释的那样,SIGHUP信号被发送给他们;任何进程都没有' t明确捕获信号终止)。
      • 这与您声称cat进程仍然存在相矛盾,但我的猜测是您错误地将交互式启动cat进程误认为是由启动的进程脚本
  • 相比之下,脚本退出后,脚本(mkfifo创建的任何FIFO 都会保持(FIFO的行为类似于文件 - 它会一直存在,直到您明确删除它为止。)

    • 但是,当您到该FIFO而没有其他进程读取时,写入命令将阻止,因此< em>出现挂起进程阻塞,直到另一个进程从FIFO读取数据)。
      • 这可能是你的情况发生的事情:因为脚本的后台进程被终止,没有人从FIFO中读取,导致尝试写入它来阻止。你错误地猜测是cat >a&命令被“卡住了”。

以下脚本在获取源代码时,会向当前shell添加函数,以便使用后台命令设置和清理保持打开的FIFO,后台命令在数据到达时对其进行处理。将其另存为文件bgfifo_funcs

#!/usr/bin/env bash

[[ $0 != "$BASH_SOURCE" ]] || { echo "ERROR: This script must be SOURCED." >&2; exit 2; }

# Set up a background FIFO with a command listening for input.
# E.g.:
#    bgfifo_setup bgfifo "sed 's/^/@ /'"
#    echo 'hi' > bgfifo # -> '@ hi'
#    bgfifo_cleanup
bgfifo_setup() {

  (( $# == 2 )) || { echo "ERROR: usage: bgfifo_setup <fifo-file> <command>" >&2; return 2; }

  local fifoFile=$1 cmd=$2

  # Create the FIFO file.
  mkfifo "$fifoFile" || return

  # Use a dummy background command that keeps the FIFO *open*.
  # Without this, it would be closed after the first time you write to it.
  # NOTE: This call inevitably outputs a job control message that looks
  #       something like this:
  #         [1]+  Stopped                 cat > ...
  { cat > "$fifoFile" & } 2>/dev/null

  # Note: The keep-the-FIFO-open `cat` PID is the only one we need to save for
  #       later cleanup.
  #       The background processing command launched below will terminate
  #       automatically then FIFO is closed when the `cat` process is killed.
  __bgfifo_pid=$!

  # Now launch the actual background command that should read from the FIFO 
  # whenever data is sent.
  { eval "$cmd" < "$fifoFile" & } 2>/dev/null || return

  # Save the *full* path of the FIFO file in a global variable for reliable
  # cleanup later.
  __bgfifo_file=$fifoFile
  [[ $__bgfifo_file == /* ]] || __bgfifo_file="$PWD/$__bgfifo_file"

  echo "FIFO '$fifoFile' set up, awaiting input for: $cmd"
  echo "(Ignore the '[1]+  Stopped ...' message below.)"
}

# Cleanup function that you must call when done, to remove
# the FIFO file and kill the background commands.
bgfifo_cleanup() {
  [[ -n $__bgfifo_file ]] || { echo "(Nothing to clean up.)"; return 0; }
  echo "Removing FIFO '$__bgfifo_file' and terminating associated background processes..."
  rm "$__bgfifo_file"
  kill $__bgfifo_pid  # Note: We let the job control messages display.
  unset __bgfifo_file __bgfifo_pid
  return 0
}

然后, source 脚本bgfifo_funcs,使用内置的. shell:

. bgfifo_funcs

Sourcing执行当前 shell 中的脚本(而不是在脚本运行后终止的子进程中),从而使脚本的函数和变量可用到目前的shell。 定义的函数在当前shell中运行,因此从函数启动的任何后台命令都可以保持活动

现在,您可以使用后台进程设置一个保持打开的FIFO,该进程在到达时按如下方式处理输入:

# Set up FIFO 'bgfifo in the current dir. and process lines sent to it
# with a sample Sed command that simply prepends '@ ' to every line.
$ bgfifo_setup bgfifo "sed 's/^/@ /'"

# Send sample data to the FIFO.
$ echo 'Hi.' > bgfifo
@ Hi.

# ...

$ echo 'Hi again.' > bgfifo
@ Hi again.

# ...

# Clean up when done.
$ bgfifo_cleanup

答案 2 :(得分:1)

您需要使用&#34; cat&#34;:

指定一个文件
 #!/bin/bash
 cat SOMEFILE >a &
 pid=$!
 echo PID $pid

虽然这看起来有点傻 - 为什么不只是&#34; cp&#34;文件(cp SOMEFILE a)?

问:你到底想要完成什么?