编者注:OP最终希望打包来自this answer的代码 作为一个脚本。所述代码创建一个保持打开的FIFO,后台命令从中读取要处理的数据。
如果我在终端中键入它,它会起作用,但如果我在脚本文件中输入这些命令并运行它,它就不会工作。
#!/bin/bash
cat >a&
pid=$!
程序似乎停留在cat>a&
$pid
没有任何价值,但cat
进程似乎存在。
答案 0 :(得分:2)
cat >a
“挂起”的原因是因为它从标准输入流(stdin,文件描述符为零)读取,默认为键盘。
添加&
会导致它在后台运行,后者会与键盘断开连接。通常,这会在后台留下暂停的作业,但是,自从退出脚本后,其后台任务将被终止(发送一个SIGHUP信号)。
编辑:虽然我按照问题中的链接进行了操作,但最初并未说明OP在该阶段实际上使用了FIFO。谢谢@ mklement0。
我不明白你在这里要做什么,但我怀疑你需要将它作为“源”文件运行,如下所示:
. gash.sh
其中gash.sh
是您脚本的名称。请注意前面的.
答案 1 :(得分:2)
cdarke's answer 包含关键指针:您的脚本不得在子进程中运行,因此您必须来源 。
根据您链接的问题,听起来您正在尝试执行以下操作:
请参阅底部了解可行的解决方案。
关于症状的解释:
运行脚本未来源(不包含.
)表示脚本在子流程中运行 ,具有以下含义:
$myPid
变量的原因。cat >a&
)被终止(正如cdarke所解释的那样,SIGHUP
信号被发送给他们;任何进程都没有' t明确捕获信号终止)。
cat
进程仍然存在相矛盾,但我的猜测是您错误地将交互式启动cat
进程误认为是由启动的进程脚本 相比之下,脚本退出后,脚本(mkfifo
)创建的任何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
)?