shell脚本内存不足

vef*_*hym 3 unix bash shell out-of-memory

我编写了以下随机数生成器shell脚本:

for i in $(seq 1 $1) #for as many times, as the first argument ($1) defines...
do 
echo "$i $((RANDOM%$2))" #print the current iteration number and a random number in [0, $2)
done
Run Code Online (Sandbox Code Playgroud)

我这样运行:

./generator.sh 1000000000 101 > data.txt
Run Code Online (Sandbox Code Playgroud)

在[0,100]中生成1行ID和随机数的行,并将该数据存储在文件中data.txt.

我想要的输出是:

1 39
2 95
3 61
4 27
5 85
6 44
7 49
8 75
9 52
10 66
...
Run Code Online (Sandbox Code Playgroud)

它适用于少量行,但对于1B,我得到以下OOM错误:

./generator.sh:xrealloc:../bash/subst.c:5179:无法分配18446744071562067968字节(分配4299137024字节)

我程序的哪一部分会产生错误?我怎么能data.txt逐行写文件?我试过更换echo线路:

echo "$i $((RANDOM%$2))" >> $3
Run Code Online (Sandbox Code Playgroud)

3美元data.txt,但我认为没有区别.

Mar*_*oij 5

问题是你的for循环:

for i in $(seq 1 $1) 
Run Code Online (Sandbox Code Playgroud)

这将首先展开$(seq 1 $1),创建一个非常大的列表,然后传递给它for.

while但是,使用我们可以读取seq逐行输出,这将占用少量内存:

seq 1 1000000000 | while read i; do
        echo $i
done
Run Code Online (Sandbox Code Playgroud)

  • 太好了!事实上,你可以通过说"读取-ri"来避免管道; 做... <<<(seq ...)` (2认同)
  • 好吧,有些东西存在陷阱 while`:如果你想在`while`循环中改变变量,它们就不会.这是因为原始shell中的变量被复制到新shell中,但更改不会影响原始shell.看到这个好读数:[我在一个管道中的循环中设置变量.它们为什么在循环结束后消失?或者,为什么我不能管道数据读取?](http://mywiki.wooledge.org/BashFAQ/024) (2认同)
  • @vefthym这不是"更好"; 对于同样的问题,它只是一个不同的解决方案.我认为这会为你理解失败的原因和一般脚本增加一些价值.Hari的答案仅适用于数字,可能最适合这个特定问题,但我还没有测试过.它也是特定于bash的非可移植语法,如果您关心它...此解决方案也适用于其他输入,例如一行文本; 它也是便携式的(fedorqui的建议不是btw). (2认同)

Har*_*non 4

$(seq 1 $1)在迭代之前计算整个列表。所以需要内存来存储整个10^9数字列表,这是很多的。

我不确定您是否可以seq延迟运行,即仅在需要时才获取下一个数字。您可以做一个简单的 for 循环:

for ((i=0; i<$1;++i))
do
  echo "$i $((RANDOM%$2))"
done
Run Code Online (Sandbox Code Playgroud)

  • “*不确定是否可以让 seq 延迟运行*”:这是一个 shell 脚本,当然可以!您可以将输出通过管道传输到“while”,它将逐行读取它(请参阅我的答案)。 (4认同)