使用Bash Shell脚本在大文件中执行多轮文本搜索需求
高效处理大型电子书列表文件的多次Bash搜索方案
嘿,我来给你捋捋怎么高效处理这个大型电子书列表的多次搜索问题——毕竟大文件反复读太费时间了,得找些省劲儿的办法!
临时多次搜索:用grep提速
如果你只是临时要做几次搜索,不想折腾预处理,那给grep加个--mmap参数就能提速不少。这个参数会用内存映射代替常规的文件读取,大文件下速度提升很明显。
因为原文件的条目是多行结构,所以需要用-A(显示匹配行后N行)和-B(显示匹配行前N行)来获取完整的条目信息,比如:
# 搜索ETEXT NO.56900的完整条目(可根据实际结构调整-A/-B的数字) grep --mmap -A 2 -B 0 "56900" your_large_file.txt # 搜索所有芬兰语的书籍 grep --mmap -B 3 -A 0 "\[Language: Finnish\]" your_large_file.txt # 搜索作者Robert Lloyd Praeger的作品 grep --mmap -B 1 -A 1 "by Robert Lloyd Praeger" your_large_file.txt
频繁搜索:先预处理成结构化文件
要是你需要反复查询这个文件,那最好先把它转成结构化的格式(比如CSV),这样后续搜索会更精准、更高效。原文件格式有点零散,我们可以用awk写个小脚本把每个条目整合成一行:
awk ' BEGIN { print "title,author,etext_no,subtitle,language" } /by / { author = substr($0, 4); gsub(/^[[:space:]]+|[[:space:]]+$/, "", author); if (current_title != "") { printf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", current_title, author, etext_no, subtitle, language; current_title = ""; subtitle = ""; language = ""; etext_no = ""; } next; } /\[Subtitle: / { subtitle = substr($0, 12); gsub(/\]$/, "", subtitle); next; } /\[Language: / { language = substr($0, 12); gsub(/\]$/, "", language); next; } /[0-9]+$/ { split($0, parts, /, [0-9]+$/); current_title = parts[1]; gsub(/^[[:space:]]+|[[:space:]]+$/, "", current_title); etext_no = substr($0, length(parts[1])+2); next; } END { # 处理最后一个未写入的条目 if (current_title != "") { printf "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n", current_title, author, etext_no, subtitle, language; } } ' your_large_file.txt > books.csv
生成books.csv之后,搜索就简单多了,比如:
# 搜索作者Robert Lloyd Praeger的作品 awk -F ',' '$2 == "\"Robert Lloyd Praeger\""' books.csv # 搜索所有芬兰语书籍 awk -F ',' '$5 == "\"Finnish\""' books.csv # 搜索ETEXT编号56898的条目 awk -F ',' '$3 == "\"56898\""' books.csv
复杂多条件搜索:用awk一次性处理
如果有多个搜索需求,不想多次读取大文件,那可以直接写个awk脚本,一次性完成所有查询,只需要读一次文件,效率拉满:
awk ' # 先定义你要搜索的目标条件 BEGIN { target_etext = "56900"; target_author = "Robert Lloyd Praeger"; target_lang = "Finnish"; print "=== 搜索结果 ==="; } /by / { current_author = substr($0, 4); gsub(/^[[:space:]]+|[[:space:]]+$/, "", current_author); next; } /\[Subtitle: / { current_subtitle = substr($0, 12); gsub(/\]$/, "", current_subtitle); next; } /\[Language: / { current_lang = substr($0, 12); gsub(/\]$/, "", current_lang); next; } /[0-9]+$/ { split($0, parts, /, [0-9]+$/); current_title = parts[1]; gsub(/^[[:space:]]+|[[:space:]]+$/, "", current_title); current_etext = substr($0, length(parts[1])+2); # 检查每个条件并输出结果 if (current_etext == target_etext) { print "\n--- ETEXT No." target_etext " ---"; print "标题: " current_title; print "作者: " current_author; print "副标题: " (current_subtitle ? current_subtitle : "无"); print "语言: " (current_lang ? current_lang : "无"); } if (current_author == target_author) { print "\n--- 作者 " target_author " ---"; print "标题: " current_title; print "ETEXT编号: " current_etext; print "副标题: " (current_subtitle ? current_subtitle : "无"); print "语言: " (current_lang ? current_lang : "无"); } if (current_lang == target_lang) { print "\n--- 语言 " target_lang " ---"; print "标题: " current_title; print "作者: " current_author; print "ETEXT编号: " current_etext; print "副标题: " (current_subtitle ? current_subtitle : "无"); } # 重置当前条目变量 current_author = ""; current_subtitle = ""; current_lang = ""; } ' your_large_file.txt
这个脚本可以根据你的需求修改BEGIN块里的目标条件,一次性输出所有匹配的结果,非常适合批量查询。
内容的提问来源于stack exchange,提问作者Azazel
相关产品推荐
相关产品推荐

