Вы могли бы рассмотреть возможность использования языка, который поддерживает md5, или, по крайней мере, кэшировать результаты md5 (я предполагаю, что город и возраст имеют ограниченный домен, который меньше, чем количество строк).
Perl имеет встроенную поддержку md5:
perl -M'Digest::MD5 qw(md5_hex)' -F'\|' -le 'if (2..eof) {
$F[$_] = md5_hex($F[$_]) for (1,3);
print join "|",@F
} else { print }'
онлайн-демонстрация: https://ideone.com/xg6cxZ (к моему удивлению ideone имеет perl в bash)
Digest::MD5
- это основной модуль, любой perl должен иметь его -M'Digest::MD5 qw(md5_hex)'
- это загружает функцию md5_hex -l
окончания строк -F'\|'
- автоматическое разбиение полей на | (это подразумевает -a и -n) 2..eof
- оператор диапазона (или триггер, как некоторые хотят его вызвать) - true между строкой 2 и концом файла $F[$_] = md5_hex($F[$_])
- заменить поле $ _ суммой md5 for (1,3)
- модификатор оператора запускает оператор для 1 и 3, алиасинг $ _ для них print join "|",@F
- выведите измененные поля else { print }
- это будет содержать заголовок
Примечание о скорости : на моем компьютере это обрабатывает ~ 100 000 строк примерно за 100 мс по сравнению с вариантом awk этого ответа , который делает 5000 строк за ~ 1 минуту 14 секунд (я не был достаточно терпелив, чтобы ждать 100 000 строк)
time perl -M'Digest::MD5 qw(md5_hex)' -F'\|' -le 'if (2..eof) { $F[$_] = md5_hex($F[$_]) for (1,3);print join "|",@F } else { print }' <sample2.txt > out4.txt
real 0m0.121s
user 0m0.118s
sys 0m0.003s
$ time awk -F'|' -v OFS='|' -i md5.awk '{ print $1,md5($2),$3,md5($4) }' <(head -5000 sample2.txt) >out2.txt
real 1m14.205s
user 0m50.405s
sys 0m35.340s
md5.awk Определяет функцию md5 следующим образом:
$ cat md5.awk
function md5(str, cmd, l, hex) {
cmd= "/bin/echo -n "str" | openssl md5 -r"
if ( ( cmd | getline l) > 0 )
hex = substr(l,0,32)
close(cmd)
return hex
}
- Я использую
/bin/echo
, потому что есть некоторые варианты оболочки, в которых у echo нет -n - I'm используя
-n
главным образом потому, что я хочу иметь возможность сравнивать результаты с perl результатами substr(l,0,32)
- на моей машине openssl md5
не возвращает только сумма, у него также есть имя файла - см .: https://ideone.com/KGMWPe - substr получает только соответствующую часть - Я использую отдельный файл, потому что он кажется намного чище, и потому что я довольно легко переключаться между реализациями функций
Как я уже говорил в начале, если вы действительно хотите использовать awk, по крайней мере кэшируйте результат инструмента openssl
.
$ cat md5memo.awk
function md5(str, cmd, l, hex) {
if (cache[str])
return cache[str]
cmd= "/bin/echo -n "str" | openssl md5 -r"
if ( ( cmd | getline l) > 0 )
hex = substr(l,0,32)
close(cmd)
cache[str] = hex
return hex
}
При вышеупомянутом кешировании результаты значительно улучшаются:
$ time awk -F'|' -v OFS='|' -i md5memo.awk '{ print $1,md5($2),$3,md5($4) }' <(head -5000 sample2.txt) >outmemo.txt
real 0m0.192s
user 0m0.141s
sys 0m0.085s
[savuso@localhost hash]$ time awk -F'|' -v OFS='|' -i md5memo.awk '{ print $1,md5($2),$3,md5($4) }' <sample2.txt >outmemof.txt
real 0m0.281s
user 0m0.222s
sys 0m0.088s
однако ваш пробег может варьироваться : sample2.txt имеет 100000 строк, с 5 различными значениями для $ 2 и 40 различными значения за 4 доллара. Реальные данные могут отличаться!
Примечание: я только что понял, что моя реализация awk не обрабатывает заголовки, но вы можете узнать это из других ответов