如何有效循环遍历Bash中的文件行?

佩德罗

我有一个example.txt大约3000行的文件,每行都有一个字符串。一个小文件示例为:

>cat example.txt
saudifh
sometestPOIFJEJ
sometextASLKJND
saudifh
sometextASLKJND
IHFEW
foo
bar

我想检查此文件中所有重复的行并将其输出。所需的输出将是:

>checkRepetitions.sh
found two equal lines: index1=1 , index2=4 , value=saudifh
found two equal lines: index1=3 , index2=5 , value=sometextASLKJND

我做了一个脚本checkRepetions.sh

#!bin/bash
size=$(cat example.txt | wc -l)
for i in $(seq 1 $size); do
i_next=$((i+1))
line1=$(cat example.txt | head -n$i | tail -n1)
for j in $(seq $i_next $size); do
line2=$(cat example.txt | head -n$j | tail -n1)
if [ "$line1" = "$line2" ]; then
echo "found two equal lines: index1=$i , index2=$j , value=$line1"
fi
done
done

但是,此脚本非常慢,需要10多个分钟才能运行。在蟒蛇它需要不到5秒钟。我试图做内存中的文件存储lines=$(cat example.txt)和做line1=$(cat $lines | cut -d',' -f$i),但是这仍然是很慢...

埃德·莫顿

有关为什么脚本如此缓慢的一些原因,请参见为什么使用Shell循环处理文本所考虑的不良做法

$ cat tst.awk
{ val2hits[$0] = val2hits[$0] FS NR }
END {
    for (val in val2hits) {
        numHits = split(val2hits[val],hits)
        if ( numHits > 1 ) {
            printf "found %d equal lines:", numHits
            for ( hitNr=1; hitNr<=numHits; hitNr++ ) {
                printf " index%d=%d ,", hitNr, hits[hitNr]
            }
            print " value=" val
        }
    }
}

$ awk -f tst.awk file
found 2 equal lines: index1=1 , index2=4 , value=saudifh
found 2 equal lines: index1=3 , index2=5 , value=sometextASLKJND

为了使您了解使用bash脚本和等效的awk脚本编写得尽可能高效的性能差异,请执行以下操作:

重击:

$ cat tst.sh
#!/bin/bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: bash 4.0 required" >&2; exit 1;; esac

# initialize an associative array, mapping each string to the last line it was seen on
declare -A lines=( )
lineNum=0

while IFS= read -r line; do
  (( ++lineNum ))
  if [[ ${lines[$line]} ]]; then
     printf 'Content previously seen on line %s also seen on line %s: %s\n' \
       "${lines[$line]}" "$lineNum" "$line"
  fi
  lines[$line]=$lineNum
done < "$1"

$ time ./tst.sh file100k > ou.sh
real    0m15.631s
user    0m13.806s
sys     0m1.029s

awk:

$ cat tst.awk
lines[$0] {
    printf "Content previously seen on line %s also seen on line %s: %s\n", \
       lines[$0], NR, $0
}
{ lines[$0]=NR }

$ time awk -f tst.awk file100k > ou.awk
real    0m0.234s
user    0m0.218s
sys     0m0.016s

这两个脚本的输出没有区别:

$ diff ou.sh ou.awk
$

上面使用第3次运行计时来避免缓存问题,并针对以下awk脚本生成的文件进行测试:

awk 'BEGIN{for (i=1; i<=10000; i++) for (j=1; j<=10; j++) print j}' > file100k

当输入文件的重复行为零(由生成seq 100000 > nodups100k)时,bash脚本的执行时间与上述时间大致相同,而awk脚本的执行速度则比上述时间快得多:

$ time ./tst.sh nodups100k > ou.sh
real    0m15.179s
user    0m13.322s
sys     0m1.278s

$ time awk -f tst.awk nodups100k > ou.awk
real    0m0.078s
user    0m0.046s
sys     0m0.015s

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何有效获取文件中的行数?

Golang:如何有效确定文件中的行数?

Redux的reducer遍历如何有效?

使用Perl有效地循环遍历具有固定长度记录字符串的文件

遍历和更新大熊猫数据框中的行的最有效方法

如何检查文件每一行上的所有路径在Bash中是否为有效路径?

如何使for循环脚本更有效?

Bash使用awk从文件中选择有效行

如何有效遍历熊猫中的日期列

为什么在for循环中使用此命令复制文件的命令在bash中有效,而在zsh中却无效?

如何使用Java有效读取Hadoop(HDFS)文件中的第一行?

如何在Linux中有效地从大文件中取出10%的随机行?

如何使循环更有效?

如何计算文件中的有效行和无效行

有效计数文件中的行

Python中更有效的循环

如何使此脚本循环遍历目录中的所有文件?

如何使此循环更有效?

如何循环遍历bash中不断增加的文件列表?

如何在Bash脚本中测试nginx配置文件是否有效?

bash有效的文件解析

在文件中更改1行的最有效方法

如何使for内部循环更有效?

如何有效地从大型文本文件中删除重复行?

如何使“for”循环遍历python 3.8中文本文件的所有行?

如何有效输入以匹配 CSV 文件中的数据

循环遍历 bash 主目录中的某些文件行

如何循环遍历列表有效负载并作为 Springboot 中的单个行项插入到数据库中?

有沒有一種有效的方法如何在 python 中獲取大文件的第 N 行?