【发布时间】:2015-01-20 06:20:14
【问题描述】:
在 bash 脚本中打开文件描述符并逐行读取文件时,脚本在处理 70K 行后终止并出现内存分配错误:
xmalloc: 无法分配 11541 字节(已分配 0 字节)
环境: 明威32 Bash:3.1.20(4)-release (i686-pc-msys) 操作系统:Windows 7
输入文件的大小:每个 1.2 GB
脚本如下:
#!/bin/bash
echo Left: $1
echo Right: $2
echo >"$1.diff"
echo >"$2.diff"
exec 4<"$1"
exec 5<"$2"
LINECOUNT=0
while [ $? == 0 ]
do
exec 0<&4
read LEFTLINE
exec 0<&5
read RIGHTLINE
if [ $? != 0 ]
then
exit -1
fi
LINECOUNT=$(($LINECOUNT + 1))
LINEMOD=$(($LINECOUNT % 1000))
if [[ $LINEMOD == 0 ]]
then
echo Line: $LINECOUNT
fi
if [ $LEFTLINE != $RIGHTLINE ]
then
echo $LEFTLINE >> "$1.diff"
echo $RIGHTLINE >> "$2.diff"
echo Mismatch found
fi
done
正如我上面所说的,脚本工作了很长时间,处理了大约 70K 行,然后终止。我认为它会终止,因为它耗尽了 32 位进程可以占用的所有内存。
脚本的目的是打开两个相同格式和长度的文件,逐行比较。它创建两个输出文件到其中写出不匹配行的位置。我不得不编写脚本,因为我可以使用的所有比较工具都因“内存不足”错误而崩溃或挂起。当我的脚本也崩溃时,我感到很惊讶。我不得不在 C++ 中重写它以使其工作。现在我试图理解为什么 bash 脚本失败了。理论上它不应该在内存中累积文件内容。相反,它应该一次只读取一行并推进文件指针。我试图了解它为什么会崩溃。也许还有另一种方法可以解决我的问题,您可以推荐我可以将其实现为 bash 脚本。
更新:测试了以下修改。它也崩溃了。
while IFS= read -u4 -r LEFTLINE && IFS= read -u5 -r RIGHTLINE
do
LINECOUNT=$(($LINECOUNT + 1))
LINEMOD=$(($LINECOUNT % 1000))
【问题讨论】:
-
您是否尝试过
read -u4而不是exec 0<&4语法?所以你可以做while IFS= read -u4 -r LEFTLINE && IFS= read -u5 -r RIGHTLINE; do echo "$LEFTLINE"; echo "$RIGHTLINE"; done 4<fileA 3<fileB -
@Mark Setchell 感谢您的有用建议。这样代码就更简洁了。我更新了问题。但是,它仍然因同样的错误而崩溃。
-
@MarkSetchell 实际上是 4gb,但这并不是重点;这可能与 bash 如何读取文件有关。如果有泄漏,那么就有泄漏 - 如果我在 OSX 上输入脚本 /dev/urandom,我也会看到进程的内存持续增长。在特定版本的 bash 中有几篇与内存泄漏相关的在线帖子,所以这可能是问题所在。不幸的是,如果发生泄漏,您可能不得不使用不同的工具而不是 bash。 this looks like it may be related。 OSX 有适合的 bash3.2
-
小提示:如果您只想清除文件,可以将
echo >"$1.diff"替换为>"$1.diff"。当你比较它们时,你应该在 $LEFTLINE 和 $RIGHTLINE 周围加上双引号 ("),否则当文件中有空格时脚本会失败。 -
我在一对相同的 20 GB 文件上运行了您的脚本,它只使用了 10 MB 的内存,这并没有增加。重击 4.1.5,x86_64。
标签: windows bash shell mingw32