在 bash 中搜索并写入一个非常大的文件的行
Search and write line of a very large file in bash
我有一个包含 60210 行的大 csv
文件。这些行包含散列、路径和文件名,如下所示:
hash | path | number | hash-2 | name
459asde2c6a221f6... | folder/..| 6 | 1a484efd6.. | file.txt
777abeef659a481f... | folder/..| 1 | 00ab89e6f.. | anotherfile.txt
....
我正在根据哈希列表过滤此文件,为了便于过滤过程,我创建并使用了此文件的简化版本,如下所示:
hash | path
459asde2c6a221f6... | folder/..
777abeef659a481f... | folder/..
过滤后的结果包含所有具有我的参考哈希基础中不存在的哈希的行。
但是为了正确分析过滤后的结果,我需要删除之前的数据。所以我的想法是读取过滤后的结果文件,搜索 hash
字段,并将其写入包含所有数据的增强结果文件中。
我使用一个循环来这样做:
getRealNames() {
originalcontent="$( cat $originalfile)"
while IFS='' read -r line; do
hash=$( echo "$line" | cut -f 1 -d " " )
originalline=$( echo "$originalcontent" |grep "$hash" )
if [ ! -z "$originalline" ]; then
echo "$originalline" > "$resultenhanced"
fi
done < "$resultfile"
}
但在实际使用中,它非常低效:对于之前的文件,这个循环大约需要 3 个小时才能 运行 在 4Go RAM,Intel Centrino 2 系统上,在我看来太长了对于这种操作。
有什么方法可以改进这个操作吗?
鉴于您的问题的性质,很难理解为什么您更愿意使用 shell 来处理如此庞大的文件,并提供像 awk
或 sed
处理它们。作为 Stéphane Chazelas points out in the wonderful answer in Unix.SE.
使用 awk
/perl
可以加快文本处理速度,您的问题就很容易解决了。此外,您通过 originalcontent="$( cat $originalfile)"
将整个文件消耗到 RAM 中,这根本不可取。
假设在原始文件和参考文件中,hash
从第一列开始并且列之间由 |
分隔,您需要使用 awk
作为
awk -v FS="|" 'FNR==NR{ uniqueHash[]; next }!( in uniqueHash)' ref_file orig_file
以上尝试仅将参考文件中的第一列条目存入内存,根本不使用原始文件。一旦我们使用了参考文件 </code>(第一列)中的条目,我们就会通过选择那些不在我们创建的数组(<code>uniqueHash
)中的行来过滤原始文件。
通过将 C
语言环境设置为 LC_ALL=C awk ...
,更改您的 locale
设置以使其更快
你对你试图做什么的解释不清楚,因为它描述了两个任务:过滤数据,然后将缺失值添加回过滤后的数据。您的示例脚本解决了第二个问题,所以我假设这就是您要在这里解决的问题。
正如我所读,您有一个包含散列和路径的过滤结果,您需要在原始文件中查找这些散列以获取其他字段值。不是将原始文件加载到内存中,而是让 grep 直接处理文件。假设单个 space(如 cut -d " "
所示)是您的字段分隔符,您也可以在 read 命令中提取散列。
while IFS=' ' read -r hash data; do
grep "$hash" "$originalfile" >> "$resultenhanced"
done < "$resultfile"
我有一个包含 60210 行的大 csv
文件。这些行包含散列、路径和文件名,如下所示:
hash | path | number | hash-2 | name
459asde2c6a221f6... | folder/..| 6 | 1a484efd6.. | file.txt
777abeef659a481f... | folder/..| 1 | 00ab89e6f.. | anotherfile.txt
....
我正在根据哈希列表过滤此文件,为了便于过滤过程,我创建并使用了此文件的简化版本,如下所示:
hash | path
459asde2c6a221f6... | folder/..
777abeef659a481f... | folder/..
过滤后的结果包含所有具有我的参考哈希基础中不存在的哈希的行。
但是为了正确分析过滤后的结果,我需要删除之前的数据。所以我的想法是读取过滤后的结果文件,搜索 hash
字段,并将其写入包含所有数据的增强结果文件中。
我使用一个循环来这样做:
getRealNames() {
originalcontent="$( cat $originalfile)"
while IFS='' read -r line; do
hash=$( echo "$line" | cut -f 1 -d " " )
originalline=$( echo "$originalcontent" |grep "$hash" )
if [ ! -z "$originalline" ]; then
echo "$originalline" > "$resultenhanced"
fi
done < "$resultfile"
}
但在实际使用中,它非常低效:对于之前的文件,这个循环大约需要 3 个小时才能 运行 在 4Go RAM,Intel Centrino 2 系统上,在我看来太长了对于这种操作。
有什么方法可以改进这个操作吗?
鉴于您的问题的性质,很难理解为什么您更愿意使用 shell 来处理如此庞大的文件,并提供像 awk
或 sed
处理它们。作为 Stéphane Chazelas points out in the wonderful answer in Unix.SE.
使用 awk
/perl
可以加快文本处理速度,您的问题就很容易解决了。此外,您通过 originalcontent="$( cat $originalfile)"
将整个文件消耗到 RAM 中,这根本不可取。
假设在原始文件和参考文件中,hash
从第一列开始并且列之间由 |
分隔,您需要使用 awk
作为
awk -v FS="|" 'FNR==NR{ uniqueHash[]; next }!( in uniqueHash)' ref_file orig_file
以上尝试仅将参考文件中的第一列条目存入内存,根本不使用原始文件。一旦我们使用了参考文件 </code>(第一列)中的条目,我们就会通过选择那些不在我们创建的数组(<code>uniqueHash
)中的行来过滤原始文件。
通过将 C
语言环境设置为 LC_ALL=C awk ...
locale
设置以使其更快
你对你试图做什么的解释不清楚,因为它描述了两个任务:过滤数据,然后将缺失值添加回过滤后的数据。您的示例脚本解决了第二个问题,所以我假设这就是您要在这里解决的问题。
正如我所读,您有一个包含散列和路径的过滤结果,您需要在原始文件中查找这些散列以获取其他字段值。不是将原始文件加载到内存中,而是让 grep 直接处理文件。假设单个 space(如 cut -d " "
所示)是您的字段分隔符,您也可以在 read 命令中提取散列。
while IFS=' ' read -r hash data; do
grep "$hash" "$originalfile" >> "$resultenhanced"
done < "$resultfile"