我有以下脚本:
#!/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 方法:
使用 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 中进行此类处理更快。
使用系统调用
$ 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 字符的行)。