减少 while 循环的 Unix 脚本执行时间
Reduce Unix Script execution time for while loop
有一个参考文件“names.txt”,其数据如下:
Tom
Jerry
Mickey
注意:文件“names.txt”中有20k行
参考文件“names.txt”中的每个键还有另一个包含多行的分隔文件,如下所示:
Name~~Id~~Marks~~Column4~~Column5
注意:分隔文件中大约有 30 列:
分隔文件看起来像:
Tom~~123~~50~~C4~~C5
Tom~~111~~45~~C4~~C5
Tom~~321~~33~~C4~~C5
.
.
Jerry~~222~~13~~C4~~C5
Jerry~~888~~98~~C4~~C5
.
.
需要从分隔文件中为文件 "names.txt" 中 "Marks" 列中具有最高值的每个键提取行。
因此,文件 "names.txt" 中的每个键在输出文件中都会有一行。
下面是我正在使用的在 unix 中截取的代码,它工作得很好,但执行脚本需要大约 2 个小时。
while read -r line; do
getData `echo ${line// /}`
done < names.txt
function getData
{
name=
grep ${name} ${delimited_file} | awk -F"~~" '{if(==name1 && >max){op=[=13=]; max=}}END{print op} ' max=0 name1=${name} >> output.txt
}
有什么方法可以并行化并减少执行时间。只能使用 shell 脚本。
优化 bash 脚本的经验法则:
输入的大小不应影响程序 运行.
的频率
您的脚本很慢,因为 bash 必须 运行 函数 20k 次,其中涉及启动 grep
和 awk
。仅仅启动程序就需要花费大量时间。因此,请尝试程序启动次数恒定的方法。
这里有一个方法:
- 处理第二个文件,这样对于每个名称,只保留具有最大标记的行。
可以通过 sort
和 awk
,或 sort
和 uniq -f
+ Schwartzian 变换来完成。
- 然后只保留名称出现在
names.txt
.
中的那些行
轻松 grep -f
sort -t'~' -k1,1 -k5,5nr file2 |
awk -F'~~' '!=last{print;last=}' |
grep -f <(sed 's/.*/^&~~/' names.txt)
sed
部分将名称转换为正则表达式,以确保仅匹配第一个字段;假设名称不包含特殊符号,如 .
和 *
.
根据第一个文件和第二个文件之间的关系,交换这两个步骤可能会更快。结果是一样的。
有一个参考文件“names.txt”,其数据如下:
Tom
Jerry
Mickey
注意:文件“names.txt”中有20k行
参考文件“names.txt”中的每个键还有另一个包含多行的分隔文件,如下所示:
Name~~Id~~Marks~~Column4~~Column5
注意:分隔文件中大约有 30 列:
分隔文件看起来像:
Tom~~123~~50~~C4~~C5
Tom~~111~~45~~C4~~C5
Tom~~321~~33~~C4~~C5
.
.
Jerry~~222~~13~~C4~~C5
Jerry~~888~~98~~C4~~C5
.
.
需要从分隔文件中为文件 "names.txt" 中 "Marks" 列中具有最高值的每个键提取行。
因此,文件 "names.txt" 中的每个键在输出文件中都会有一行。
下面是我正在使用的在 unix 中截取的代码,它工作得很好,但执行脚本需要大约 2 个小时。
while read -r line; do
getData `echo ${line// /}`
done < names.txt
function getData
{
name=
grep ${name} ${delimited_file} | awk -F"~~" '{if(==name1 && >max){op=[=13=]; max=}}END{print op} ' max=0 name1=${name} >> output.txt
}
有什么方法可以并行化并减少执行时间。只能使用 shell 脚本。
优化 bash 脚本的经验法则:
输入的大小不应影响程序 运行.
您的脚本很慢,因为 bash 必须 运行 函数 20k 次,其中涉及启动 grep
和 awk
。仅仅启动程序就需要花费大量时间。因此,请尝试程序启动次数恒定的方法。
这里有一个方法:
- 处理第二个文件,这样对于每个名称,只保留具有最大标记的行。
可以通过sort
和awk
,或sort
和uniq -f
+ Schwartzian 变换来完成。
- 然后只保留名称出现在
names.txt
.
中的那些行 轻松grep -f
sort -t'~' -k1,1 -k5,5nr file2 |
awk -F'~~' '!=last{print;last=}' |
grep -f <(sed 's/.*/^&~~/' names.txt)
sed
部分将名称转换为正则表达式,以确保仅匹配第一个字段;假设名称不包含特殊符号,如 .
和 *
.
根据第一个文件和第二个文件之间的关系,交换这两个步骤可能会更快。结果是一样的。