Isso fará isso (em cerca de 40 segundos no meu sistema):
#!/bin/bash
[ "$BASHPID" = "$$" ] || { echo "Must run in a new process group"; exit 1; }>&2
cnt0() { cnt0=$#; }
cnt1() { cnt1=$#; }
tmpd=
trap 'rm -rf "$tmpd"; exit 1' INT HUP QUIT EXIT
tmpd=$(mktemp -d)
mkfifo "$tmpd/fifo"
exec 4<>"$tmpd/fifo"
rm -rf "$tmpd"
trap - INT HUP QUIT EXIT
open_all()
{
cnt0 /proc/self/fd/*;
while exec {fd}</dev/null; do :; done;
cnt1 /proc/self/fd/*;
nopened=$((cnt1-cnt0));
echo $nopened >&4;
cat /proc/sys/fs/file-nr
if ((nopened)); then
sleep 10000000
fi
}
( open_all )&
while :; do
if read nopened <&4 && ((nopened)); then
( open_all )&
continue
fi
break
done
kill -TERM -$$
Funciona abrindo /dev/null
em um subshell o maior número de vezes possível (deve funcionar cerca de 1000-4000 vezes, dependendo do seu ulimit -n
).
Se pelo menos um filedescriptor for aberto, o pai será notificado por meio de um pipe e a subshell será suspensa com sleep
. O processo pai responde a uma alocação fd bem-sucedida no filho, continuando o processo em outra sub-shell até que uma sub-camada falhe.
/proc/sys/fs/file-nr
é cat
em cada iteração para que você saiba como o processo continua.
No final do processo, você deve receber algo como:
...
778192 0 786806
779248 0 786806
780272 0 786806
781264 0 786806
782256 0 786806
783280 0 786806
784304 0 786806
785328 0 786806
786352 0 786806
./open_all: line 35: cannot redirect standard input from /dev/null: Too many open files in system
./open_all: line 18: fd: Too many open files in system
Terminated
Uma coisa interessante que aprendi com isso é que os filedescriptors duplicados (de dup ou fork) não contam para o limite (gerar um processo pai com muitos descritores de arquivos não aumenta a contagem).