入力ファイルを一度解析して2つの別々のストリームに送信し、並べて表示する方法は?

入力ファイルを一度解析して2つの別々のストリームに送信し、並べて表示する方法は?

次のスクリプトがあります。

#!/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

上記のスクリプトの問題は、各列/ストリームに対してファイルを2回読み取って解析する必要があることです。理想的には、すべての行をソートして一意にし、一度だけ入力として使用したいと思います。

sortファイルを一度だけ(&uniq)解析し、出力を2つの異なるストリームにリダイレクトし、行を並べて表示してより大きなファイルをより迅速に処理できるように、上記のスクリプトを変換するにはどうすればよいですか。


私のもう一つの試みは次のとおりです。

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

ただし、ストリームを個別に印刷します(並べて印刷しません)。

paste理想的には、次のように使用したいのですが、teeエラーが発生します。

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

答え1

2つの項目を並べて表示するには、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
    

    これはおそらくたくさんシェルでこれらの処理を実行するよりも高速です。

  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言及された問題がたくさんあります。シェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?

ここでは以下を使用しますperl

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

より一般的な質問は、次のように重複または変形しているようです。tee + cat:出力を複数回使用し、結果を連結します。

2つの行が同じに整列しているため(つまり、1sort -u行だけ保持されているため)、同じで同じMD5チェックサムを持ちます。LC_ALL=C sort -uバイト間比較に基づいて順序と一意性を使用できますstrcoll()。また、一部の実装では、長すぎる行、終了していない行、またはNUL文字を含む行を含むテキストではなく入力をブロックすることがsortあります。C

関連情報