입력 파일을 한 번 구문 분석하여 두 개의 별도 스트림으로 보내고 나란히 표시하는 방법은 무엇입니까?

입력 파일을 한 번 구문 분석하여 두 개의 별도 스트림으로 보내고 나란히 표시하는 방법은 무엇입니까?

다음 스크립트가 있습니다.

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

    이것은 아마도많은쉘에서 이러한 처리를 수행하는 것보다 빠릅니다.

  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: 출력을 여러 번 사용한 다음 결과를 연결합니다.

두 행이 동일하게 정렬되기 때문에(즉, sort -u한 행만 유지됨) 동일하며 동일한 MD5 체크섬을 갖습니다. LC_ALL=C sort -u바이트 간 비교를 기반으로 순서 및 고유성을 사용할 수 있습니다 strcoll(). 또한 일부 구현 에서는 너무 긴 줄, 종료되지 않은 줄 또는 NUL 문자가 포함된 줄이 sort포함된 텍스트가 아닌 입력을 차단할 수도 있습니다 .C

관련 정보