arrays - 减少 'While read' 循环的处理时间

标签 arrays shell awk while-loop

shell 脚本新手..

我有一个巨大的 csv 文件,长度不等 f11,例如

“000000aaad000000bhb200000uwwed...”
“000000aba200000bbrb2000000wwqr00000caba2000000bhbd000000qwew...”
. .

将字符串拆分为 10 个大小后,我需要 6-9 个字符。然后我必须使用定界符“|”加入他们的行列,比如

0aaa|0bhb|uwwe...
0aba|bbrb|0wwq|caba|0bhb|0qwe...

并将处理后的f11与其他字段加入

这是处理 10k 条记录所花费的时间 ->

真正的 4m43.506s
用户 0m12.366s
系统 0m12.131s

20K 条记录 ->
真正的5m20.244s
用户 2m21.591s
系统 3m20.042s

80K 条记录(约 370 万条 f11 使用“|”拆分和合并)->

真正的 21 米 18.854 秒
用户 9m41.944s
系统 13m29.019s

我预计处理 650K 条记录的时间是 30 分钟(大约 5600 万次 f11 拆分和合并)。有什么优化方法吗?

while read -r line1; do
    f10=$( echo $line1 | cut -d',' -f1,2,3,4,5,7,9,10)
    echo $f10 >> $path/other_fields
    
    f11=$( echo $line1 | cut -d',' -f11 )
    f11_trim=$(echo "$f11" | tr -d '"')
    echo $f11_trim | fold -w10 > $path/f11_extract 

    cat $path/f11_extract | awk '{print $1}' | cut -c6-9 >> $path/str_list_trim
    
    arr=($(cat $path/str_list_trim))
    printf "%s|" ${arr[@]} >> $path/str_list_serialized
    printf '\n' >> $path/str_list_serialized
    arr=()
    
    rm $path/f11_extract
    rm $path/str_list_trim

done < $input
sed -i 's/.$//' $path/str_list_serialized
sed -i 's/\(.*\)/"\1"/g' $path/str_list_serialized

paste -d "," $path/other_fields $path/str_list_serialized > $path/final_out

最佳答案

由于以下原因,您的代码效率不高:

  • 在循环中调用多个命令,包括 awk。
  • 生成许多中间时间文件。

你可以用 awk 完成这项工作:

awk -F, -v OFS="," '                                    # assign input/output field separator to a comma
{
    len = length($11)                                   # length of the 11th field
    s = ""; d = ""                                      # clear output string and the delimiter
    for (i = 1; i <= len / 10; i++) {                   # iterate over the 11th field
        s = s d substr($11, (i - 1) * 10 + 6, 4)        # concatenate 6-9th substring of 10 characters long chunks
        d = "|"                                         # set the delimiter to a pipe character
    }
    $11 = "\"" s "\""                                   # assign the 11th field to the generated string
} 1' "$input"                                           # the final "1" tells awk to print all fields

输入示例:

1,2,3,4,5,6,7,8,9,10,000000aaad000000bhb200000uwwed
1,2,3,4,5,6,7,8,9,10,000000aba200000bbrb2000000wwqr00000caba2000000bhbd000000qwew

输出:

1,2,3,4,5,6,7,8,9,10,"0aaa|0bhb|uwwe"
1,2,3,4,5,6,7,8,9,10,"0aba|bbrb|0wwq|caba|0bhb|0qwe"

关于arrays - 减少 'While read' 循环的处理时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69717681/

相关文章:

linux - 使用awk从日志文件中提取包含文本和数字的特定行

c - 在 C 中访问多维字符串数组的元素

bash - 提取包含多个部分的部分文件名

regex - sed:用匹配的模式替换第 n 个词?

linux - Unix Diff 命令比较 2 个 txt 文件之间的差异并生成更多命令

linux - Shell GNU-Screen -X Stuff 问题

linux - 如何在具有 AWK 语句的 bash 脚本中使用 --enable-switch

javascript - Node 快速循环 session 数据

php - 获取数组中的最后一个值

c - 从 C 文件中排序单词和数字