Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash脚本,can';在函数中调用时,不要等待eval命令完成_Bash - Fatal编程技术网

Bash脚本,can';在函数中调用时,不要等待eval命令完成

Bash脚本,can';在函数中调用时,不要等待eval命令完成,bash,Bash,我试图做的是创建一个通用的异步命令运行程序,它允许我在后台运行命令,并在不阻塞我正在使用的shell的情况下获取其输出和代码(想想串行)。对于大多数命令,我可以执行以下操作: FUNCwaitForCommand() { wait "$1" echo $? > "code.txt" } ls > "output.txt" & pid=$! FUNCwaitForCommand $pid & FUNCwaitForCommand() {

我试图做的是创建一个通用的异步命令运行程序,它允许我在后台运行命令,并在不阻塞我正在使用的shell的情况下获取其输出和代码(想想串行)。对于大多数命令,我可以执行以下操作:

FUNCwaitForCommand() {
    wait "$1"
    echo $? > "code.txt"
}
ls > "output.txt" &
pid=$!
FUNCwaitForCommand $pid &
FUNCwaitForCommand() {                                                                                    
    wait $1                                                                                               
    echo $? > code                                                                                        
}
eval "ls > output.txt &"
pid=$!
FUNCwaitForCommand $pid &
但是,这不适用于组合命令,例如

(cat < somefifo)
但等待并不等待。我可以通过执行以下操作使其等待完成,直到流程完成:

while kill -0 "$1"; do wait "$1"; done
不是等待,而是它给我的代码是127,而不是运行的命令的代码。如果我在pid集合之后直接进行等待

eval "ls > output.txt &"
pid=$!
wait $pid
它等待的过程很好,但显然它没有背景和释放壳回给我

我不擅长bash,但它看起来好像函数内部与eval不在同一个子shell中,因此它无法识别后台进程,尽管我不知道为什么它只在使用eval时才这样做,而在使用正常执行方法时却不这样做。

解释 正如您不能使用:

sleep 5 & pid=$!
wait $pid &
你也不能把等待放在后台函数中。也就是说,您可以运行:

但你不能跑:

这是因为进程只能为其子进程等待()。当你用
&
把一个新的孩子从壳中分离出来时,你不再是父母,而是兄弟姐妹。因此,这不是特定于shell的行为,而是通用的UNIX语义——在任何语言中都会出现相同的错误


变通办法 确保退出状态记录由记录其退出状态的进程的直接父进程完成,即使该父进程本身位于相对于原始shell的后台

这样,在父进程中,每个进程都有一个临时目录到顶级PID的映射(很容易用于检查完成情况),并且可以在该目录中查找有关任何进程的更多信息。

正如您不能使用:

sleep 5 & pid=$!
wait $pid &
你也不能把等待放在后台函数中。也就是说,您可以运行:

但你不能跑:

这是因为进程只能为其子进程等待()。当你用
&
把一个新的孩子从壳中分离出来时,你不再是父母,而是兄弟姐妹。因此,这不是特定于shell的行为,而是通用的UNIX语义——在任何语言中都会出现相同的错误


变通办法 确保退出状态记录由记录其退出状态的进程的直接父进程完成,即使该父进程本身位于相对于原始shell的后台


这样,在父进程中,每个进程都有一个临时目录到顶级PID的映射(很容易用于检查是否完成),并且可以在该目录中查找有关所涉及的任何进程的更多信息。

与它作为一个函数无关,与函数相关的一切。也就是说,
FUNCwaitForCommand$pid&
不会像
wait$pid&
那样工作。这不仅与函数无关,顺便说一句,也与
eval
无关。请在将来更努力地使你的问题变得最小——简化复制机的任何方面,而这些方面实际上并不是重现问题所必需的。根据我的测试,我确实相信这是一个最小的例子。问题似乎在于,正如您所看到的,我认为它在不使用eval时有效。我记得今天早上早些时候在调试和制定这个问题时测试了它,我记得它起作用了。这段代码已经在生产环境中运行了几个月,这一事实支持了这一想法。然而,像往常一样,人脑并不像我们想象的那么可靠,所以我带来了不完整的信息。这与它是一个功能无关,一切都与你的功能背景有关。也就是说,
FUNCwaitForCommand$pid&
不会像
wait$pid&
那样工作。顺便说一句,这不仅与函数无关,也与
eval
无关。请在将来更努力地使你的问题变得最小——简化复制机的任何方面,而这些方面实际上并不是重现问题所必需的。根据我的测试,我确实相信这是一个最小的例子。问题似乎在于,正如您所看到的,我认为它在不使用eval时有效。我记得今天早上早些时候在调试和制定这个问题时测试了它,我记得它起作用了。这段代码已经在生产环境中运行了几个月,这一事实支持了这一想法。然而,像往常一样,人脑并不像我们想象的那样可靠,所以我带来了不完整的信息。
wait$pid
而不是
wait“$1”
?谢谢,将pid写入一个文件是我最初完成这项工作所缺少的部分。不知道为什么我没有想到这一点,但利用这个想法,我能够让它正常工作。@codeforester,…所以,我确实在这个原始版本的函数中嵌套了这个错误(折叠到最初的5分钟编辑窗口中),但是,在添加您的评论时,答案中仍然存在的
$pid
条目都是我想要的条目,因为它们要么是顶级的,要么是子shell中的作用域。
wait$pid
而不是
wait“$1”
?谢谢,将pid写入一个文件是我最初做这项工作所缺少的部分。不知道为什么我没有想到这一点,但利用这个想法,我能够让它正常工作。@codeforester,…所以,我确实在这个(折叠的)原始版本的函数中嵌套了这个错误
sleep 5 & pid=$!
waitForCommand() { wait "$@"; }
waitForCommand "$pid" &
tempdir_top=$(mktemp -t -d bgdir.XXXXXX)
declare -g -A tempdirs=( )

runBackgroundCommand() {
  (( "$#" == 1 )) || { echo "Usage: runBackgroundCommand 'command'" >&2; return 1; }
  local cmd tempdir
  cmd=$1
  tempdir=$(mktemp -d "$tempdir_top/proc.XXXXXX")
  {
    printf '%s\0' "$cmd" >"$tempdir/cmd"
    eval "$cmd" >"$tempdir/stdout" 2>"$tempdir/stderr" & pid=$!
    printf '%s\n' "$pid" >"$tempdir/pid"
    wait "$1"; retval=$?
    printf '%s\n' "$retval" >"$tempdir/retval"
  } &
  tempdirs[$tempdir]=$!
}

# example usage
runBackgroundCommand "sleep 5"
runBackgroundCommand "sleep 10"