如何解析一次输入文件并将其发送到两个单独的流并并排显示?

如何解析一次输入文件并将其发送到两个单独的流并并排显示?

我有以下脚本:

#!/usr/bin/env bash
# Script to generate MD5 hash for each line.
[ $# -eq 0 ] && { echo "Usage: $0 file"; exit 1; }
file=$1
shopt -s expand_aliases
alias calc_md5='while read -r line; do md5sum <<<$line; done'
paste <(sort "$file" | uniq | calc_md5) <(sort "$file" | uniq)
times

它并排打印每行的 MD5 校验和,这正是我所需要的。例如:

$ ./md5_lines.sh file.dat
5c2ce561e1e263695dbd267271b86fb8  - line 1
83e7cfc83e3d1f45a48d6a2d32b84d69  - line 2
0f2d633163ca585e5fc47a510e60f1ff  - line 3
73bb3632fc91e9d1e1f7f0659da7ec5c  - line 4

上述脚本的问题是它需要为每个列/流读取和解析文件两次。理想情况下,我想对所有行进行排序并使它们唯一,并仅将其用作输入一次。

如何将上述脚本转换为仅解析文件一次(sort& uniq),然后将输出重定向到两个不同的流并并排显示行,以便它可以更快地处理较大的文件?


这是我的另一个尝试:

tee >(calc_md5) >(cat -) \
      < <(sort "$file" | uniq) \
      >/dev/null
times

但它单独打印流(不是并排)。

理想情况下,我想以paste与 相同的方式使用tee,但是它给了我错误:

$ paste >(cat -) >(cat -) </etc/hosts
paste: /dev/fd/63: Permission denied

答案1

如果你想并排显示两个东西,你可以使用 printf 进行格式化打印。

#!/bin/bash
sort "$1" | uniq | while read line; do
    md5=$(md5sum <<< "$line")
    printf "%s %s\n" "$md5" "$line"
done 
times

答案2

几种 Perl 方法:

  1. 使用 Perl 获取 md5sum

    $ perl -ne 'BEGIN{  
                    use Digest::MD5  qw(md5_hex)
                } 
                $k{$_}=md5_hex("$_"); 
                END{
                    print "$k{$_} - $_" for sort keys(%k)
                }' file
    5c2ce561e1e263695dbd267271b86fb8 - line 1
    83e7cfc83e3d1f45a48d6a2d32b84d69 - line 2
    0f2d633163ca585e5fc47a510e60f1ff - line 3
    73bb3632fc91e9d1e1f7f0659da7ec5c - line 4
    d82912361d84a675530f5e32aa6eeda1 - line 5
    

    是的,这是一个单行:

    perl -ne 'BEGIN{use Digest::MD5  qw(md5_hex)} $k{$_}=md5_hex("$_"); END{print "$k{$_} - $_" for sort keys(%k)}' file
    

    这应该是很多比在 shell 中进行此类处理更快。

  2. 使用系统调用

    $ perl -lne 'chomp($md=`md5sum <<<"$_"`); print "$md $_" if !$seen{$_}++' file
    83e7cfc83e3d1f45a48d6a2d32b84d69  - line 2
    0f2d633163ca585e5fc47a510e60f1ff  - line 3
    d82912361d84a675530f5e32aa6eeda1  - line 5
    73bb3632fc91e9d1e1f7f0659da7ec5c  - line 4
    5c2ce561e1e263695dbd267271b86fb8  - line 1
    

答案3

进行循环while read有许多提到的问题为什么使用 shell 循环处理文本被认为是不好的做法?

在这里,我会使用perl

sort -u < "$file" | perl -MDigest::MD5=md5_hex -lpe '
  $_ = md5_hex($_) . " - " . $_'

您更普遍的问题看起来像是以下的重复或变体tee + cat:多次使用输出,然后连接结果

请注意,并不是因为两行排序相同(即sort -u仅保留一行),它们就相同并具有相同的 MD5 校验和。您可能希望使用LC_ALL=C sort -u基于字节到字节比较的排序和唯一性strcoll()(另请注意,某些sort实现可能会因非文本输入而阻塞,这些输入在C语言环境中仍会包含太长的行、未终止的行或包含 NUL 字符的行)。

相关内容