Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 如何在Bash中高效地循环文件的行?_Linux_Bash_Shell_Scripting - Fatal编程技术网

Linux 如何在Bash中高效地循环文件的行?

Linux 如何在Bash中高效地循环文件的行?,linux,bash,shell,scripting,Linux,Bash,Shell,Scripting,我有一个文件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:

我有一个文件
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
我想检查这个文件中所有重复的行并输出它们。所需的输出将是:

>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分钟。在python中,只需不到5秒。。。我试图通过执行
lines=$(cat example.txt)
line1=$(cat$lines | cut-d','-f$I)
将文件存储在内存中,但这仍然非常慢…

请参阅脚本如此慢的一些原因

$ 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
两个脚本的输出没有区别:

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

awk 'BEGIN{for (i=1; i<=10000; i++) for (j=1; j<=10; j++) print j}' > file100k
请参阅以了解脚本如此缓慢的一些原因

$ 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
两个脚本的输出没有区别:

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

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

当您不想使用
awk
(一个很好的工作工具,只解析一次输入)时, 你可以把这些线重复几次。排序很昂贵,但此解决方案避免了您尝试的循环

grep -Fnxf <(uniq -d <(sort example.txt)) example.txt

grep-Fnxf当您不想使用
awk
时(这是一个很好的工作工具,只解析输入一次), 你可以把这些线重复几次。排序很昂贵,但此解决方案避免了您尝试的循环

grep -Fnxf <(uniq -d <(sort example.txt)) example.txt

grep-Fnxf来演示一种相对高效(在语言和运行时的限制范围内)的本地bash方法,您可以在以下位置看到它在在线解释器中运行:

#/bin/bash
“|[123].*)echo中的$BASH_版本错误:需要BASH 4.0”>&2;出口1;;以撒
#初始化关联数组,将每个字符串映射到它所在的最后一行
声明-A行=()
lineNum=0
而IFS=读取-r行;做
lineNum=$((lineNum+1))
如果[${line[$line]}]];然后
printf'找到两条相等的行:index1=%s、index2=%s、value=%s\n'\
“${lines[$line]}”“$lineNum”“$line”
fi
行[$line]=$lineNum

完成以演示一种相对高效(在语言和运行时的限制范围内)的本地bash方法,您可以在以下位置看到它在联机解释器中运行:

#/bin/bash
“|[123].*)echo中的$BASH_版本错误:需要BASH 4.0”>&2;出口1;;以撒
#初始化关联数组,将每个字符串映射到它所在的最后一行
声明-A行=()
lineNum=0
而IFS=读取-r行;做
lineNum=$((lineNum+1))
如果[${line[$line]}]];然后
printf'找到两条相等的行:index1=%s、index2=%s、value=%s\n'\
“${lines[$line]}”“$lineNum”“$line”
fi
行[$line]=$lineNum

看到了。@EdMorton我编辑了它,我想现在它是clearSounds,你应该看看sort和uniq命令。@EdMorton我想要一个有效的解决方案,如果文件有十行,我可以用我的代码轻松地完成它,但是可以编辑它。@Pedro,…如果你想要一个最高效率的解决方案,bash是一个错误的工具。尽管所有的命令替换、外部命令调用,&c。让你的代码以10个数量级为基数(也就是说,是的,成百上千倍)比它可能的效率低很多——如果你对性能不太敏感,最好使用另一种语言,那么一个
while read
循环通常是正确的。参见。@EdMorton我编辑过它,我想现在是clearSounds了,你应该看看sort和uniq命令。@EdMorton我想要一个高效的解决方案,如果文件有十行,我可以用我的代码轻松地完成它,但是可以编辑它。@Pedro,…如果你想要一个最高效的解决方案,bash是这个工作的错误工具。尽管所有的命令替换、外部命令调用,&c。让你的代码以10个数量级为基数(也就是说,是的,成百上千倍)比它可能的效率低很多——如果你对性能不太敏感,最好使用不同的语言,那么在阅读时使用
循环通常是正确的。我强烈不同意你的链接。OP使用的实践比链接答案所批评的要慢几个数量级;用被描述为缓慢或高效的代码替换他们的代码将使其速度比现在快数百倍。相比于为每行输入设置子shell和可执行文件的成本,这种联系中所描述的原因完全是无足轻重的。OP的代码逐字节读取的速度将比现在快得多。链接的文章介绍了这一点,并用外行术语解释了这是一个问题的原因,例如:
调用一个工具是有成本的……必须创建一个进程,必须加载、初始化、清理工具,销毁进程并等待。调用cut就像打开厨房抽屉,拿起刀子,使用它,清洗它,擦干它,把它放回抽屉
。在Mac上,我看到bash版本的第三次运行时间为7.079秒,而awk为0.328秒,ksh93为2.0秒(小于3.2秒,在一个10个数量级的基数内)。bash代码的唯一变化是进行版本检查并使用
typeset-A
而不是
declare-A
。我强烈反对您的链接。OP使用的实践比链接答案所批评的要慢几个数量级;将他们的代码替换为那些被描述为缓慢或高效的代码将使其速度比现在快数百倍。相比于
fork()
ing subshell和
exec()
ing separate
cat
head