Bash文件描述符耗尽

5

我正在做一项项目,并且我想为我找到的解决方案做出贡献:

代码是这样的:

while true
do
     while read VAR
     do
        ......
     done < <(find ........ | sort)
     sleep 3
done

日志中的错误如下:

/dir/script.bin: redirection error: cannot duplicate fd: Too many open files
/dir/script.bin: cannot make pipe for process substitution: Too many open files
/dir/script.bin: line 26: <(find "${DIRVAR}" -type f -name '*.pdf' | sort): Too many open files
find: `/somedirtofind': Too many open files
/dir/script.bin: cannot make pipe for process substitution: Too many open files
/dir/script.bin: cannot make pipe for process substitution: Too many open files
/dir/script.bin: line 26: <(find "${DIRVAR}" -type f -name '*.pdf' | sort): ambiguous redirect

我发现使用命令:ls -l /proc/3657(这里填写pid)/fd可以查看文件描述符不断增加的情况。
这是在Debian 7、GNU bash版本为4.2.37(1)-release (i486-pc-linux-gnu)的环境下观察到的。
2个回答

4

The solution that worked for me is:

while true
do
     find ........ | sort | while read VAR
     do
     done
     sleep 3
done

除了在结尾避免子shell外,必须存在某种泄漏。

现在,执行ls时,在进程目录中看不到文件描述符。

邮件发送至错误跟踪器:

The minimum reproduceable code is:

#!/bin/bash
function something() {
  while true
  do
    while read VAR
    do
      dummyvar="a"
    done < <(find "/run/shm/directory" -type f | sort)
    sleep 3
  done
}
something &

Which fails with many pipes fd open.

Changing the While feed to this:

#!/bin/bash
function something() {
  find "/run/shm/directory" -type f | sort | while true
  do
    while read VAR
    do
      dummyvar="a"
    done
    sleep 3
  done
}
something &

Works completely normal.

However, removing the call as function in background:

#!/bin/bash
while true
do
  while read VAR
  do
    dummyvar="a"
  done < <(find "/run/shm/debora" -type f | sort)
  sleep 3
done

But executing the script with ./test.sh & (in background), works
without problems too.

@konsolebox 最重要的部分是将多个PDF文件合并成一个。这里使用了条件语句、sed命令、向日志输出echo命令以及将cat和echo命令输出到同一日志文件中。最后删除原始的PDF文件。 - JorgeeFG
你是否在后台运行一个进程? - konsolebox
我遇到了同样的问题。使用 while...done < <(foo) 的原因之一是因为 foo 在新进程中执行,但循环体将在当前进程中执行,因此循环体可以与其他代码共享变量。而使用 foo | while ...donefoo 在当前进程中,而循环体在新进程中,因此循环体写入的任何变量都不会在其他地方可见。切换哪个部分在哪个进程中执行可能会解释为什么文件描述符被清理或未被清理(当子进程退出时)。 - Warbo
3
我知道这已经有一段时间了,但他们回复我说这个问题在Bash 4.3中得到了修复。 - JorgeeFG
@JorgeeFG 我可能在5.0.17中遇到了一个回归问题,因为你的解决方法对我有效。 - user1133275
显示剩余4条评论

0
我遇到了同样的问题,并尝试了你建议的方法。你说:

但是在后台执行脚本 ./test.sh & 也可以正常工作。

所以对我有效的方法是在后台运行并等待每次完成:
while true
do
     while read VAR
     do
        ......
     done < <(find ........ | sort) &
     wait
done

另一个有效的方法是将创建描述符的代码放入一个函数中,而不在后台运行:
function fd_code(){
     while read VAR
     do
        ......
     done < <(find ........ | sort)
}

while true
do
     fd_code
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接