Bash脚本编写2个文件,每个输入行使用不同的输出元素

时间:2012-11-08 12:23:17

标签: linux bash sed

我想使用bash脚本将1个输入文件处理成2个输出文件,每个文件包含与输入文件相同数量的行,但输入行的不同部分。特别是其中一个输出文件必须包含输入行选择的md5hash(每行计算哈希值,而不是每个文件计算!):

所以

Input_file.txt:** 3个字段,以空格分隔

12347654 abcdfg 1verylongalpha1234numeric1

34543673 nvjfur 2verylongalpha1234numeric2

75868643 vbdhde 3verylongalpha1234numeric3

输出file_1.txt必须如下所示:(左侧字段为MD5sum,右侧字段为输入文件中的field3,也包含在MD5hash中):

12df5j754G75f738fjk3483df3fdf9 1verylongalpha1234numeric1

3jf75j47fh4G84ka9J884hs355jhd8 2verylongalpha1234numeric2

4hf7dn46chG4875ldgkk348fk345d9 3verylongalpha1234numeric3

输出file_2.txt必须如下所示:(输入文件中的field1和field2 + MD5HASH)

12347654 abcdfg 12df5j754G75f738fjk3483df3fdf9

34543673 nvjfur 3jf75j47fh4G84ka9J884hs355jhd8

75868643 vbdhde 4hf7dn46chG4875ldgkk348fk345d9

我已经有了一个可以完成工作的脚本,但它的表现非常糟糕:(下面的脚本可能无法正常工作,这是我的头脑,这里没有linux,我写这个,对不起)

#!/bin/bash

While read line

do   MD5_HASH=${sed -nr 's/^[[:digit:]]*\s[[:alpha:]]*\s([[:alnum:]]*)/\1/p' <<<$line     | md5sum} 
read $line DATA_PART1 DATA_PART2 DATA_PART3

echo "$MD5_HASH $DATA_PART3" >> file_1.txt    ##append file_2.txt in loop THIS IS WHERE IT GETS HORRIBLY SLOW!

echo "$DATA_PART1 $DATA_PART2 $MD5_HASH" 
done < input_file.txt > file_2.txt

exit 0

我认为“将stdout重定向到带附加构造的文件”'&gt;&gt;'负责缓慢的表现,但我想不出另一种方式。它在循环中因为我必须计算每行的md5hash。

(哦,sed命令是必要的,因为实际上进入MD5SUM的部分只能用正则表达式和非常复杂的模式捕获)

所以任何人都有建议吗?

5 个答案:

答案 0 :(得分:2)

您的bash脚本可以稍微整理一下。请注意,read命令可以将3个字段读入单独的变量:

#!/bin/bash
rm -f file_1.txt file_2.txt    
While read f1 f2 f3; do
    hash=$(md5sum <<< $f3)
    printf "%s %s\n" "$hash" "$f3" >> file_1.txt
    printf "%s %s %s\n" "$f1" "$f2" "$hash" >> file_2.txt
done < input_file.txt

答案 1 :(得分:1)

这是我使用功能齐全的语言的一种情况,例如Python。

虽然您可以通过仅使用标准gnu工具找到一种方法来实现这一点,但您最终可能会得到一个解决方案:

  • 非常复杂,难以阅读和维护
  • 效率低下,因为这些工具无法提供直接的方法。

1。用Python创建第一个文件

from hashlib import md5
with open('input.txt', 'r') as infile:
    for l in infile:
        if not l.strip(): continue
        parts = l.strip().split()
        print md5(parts[2]).hexdigest(), parts[2]

2。在Python中创建第二个文件

from hashlib import md5
with open('input.txt', 'r') as infile:
    for l in infile:
        if not l.strip(): continue
        parts = l.strip().split()
        print parts[0], parts[1], md5(parts[2]).hexdigest()

我不确定你计算校验和的字段;但是,当然,你可以在你想要的任何一个领域进行计算;你还可以在线上执行更复杂的基于正则表达式的匹配;你可以通过一次输出两个文件来加快速度,从而避免两次计算md5。

3。一次创建两个文件

from hashlib import md5
with open('infile.txt','r')  as infile, open('out1.txt','w') as out1, open('out2.txt','w') as out2:
    for l in infile:
        if not l.strip(): continue
        parts = l.strip().split()
        _checksum = md5(parts[2]).hexdigest()
        out1.write("%s\n" % " ".join([ _checksum, parts[2] ]))
        out2.write("%s\n" % " ".join([ parts[0], parts[1], _checksum ]))

4。与#1相同,但从标准输入

读取
import sys
from hashlib import md5
for l in sys.stdin:
    if not l.strip(): continue
    parts = l.strip().split()
    print md5(parts[2]).hexdigest(), parts[2]

答案 2 :(得分:1)

无法确定要计算md5的字符串,这个单行在整行上执行,并在'file1'和'file2'中输出处理后的'input_file':

awk '{ "md5 -q -s \""$0"\"" | getline md5; 
     print md5" "$3 > "file1"; 
     print $1" "$2" "md5 > "file2" }' input_file

希望有所帮助......

答案 3 :(得分:0)

你可以从bash同时写两个文件,如下所示:

; function to remove extraneous filename output from md5sum.  omit on 
; OS X, which has 'md5' command that already works this way.
md5() { set -- $(md5sum "$@"); echo "$1"; }

exec 3>file_1.txt 4>file_2.txt
while read left middle right; do
  md5="$(echo -n "$right" | md5)"
  echo >&3 "$md5 $right"
  echo >&4 "$left $middle $md5"
done <input_file.txt
exec 3>&- 4>&-

假设你的例子中有简单的空格分隔的字段;你当然还需要做任何sed魔法来获得MD5总和的实际目标。

但是,它不会很有效率。为了获得更好的性能,你应该使用像Perl或Python这样的东西,它可以同时进行你使用sed的字段提取和MD5计算,所有这些都在循环过程中比shell快得多。输入线。 Perl例子:

perl -MDigest::MD5=md5_hex -lane '
  BEGIN { open $f1, ">file_1.txt"; open $f2, ">file_2.txt" }
  $md5 = md5_hex $F[2];
  print $f1 "$md5 $F[2]";
  print $f2 "$F[0] $F[1] $md5";
' input_file.txt

答案 4 :(得分:0)

您可以通过管道和并行来提高效率。

根据您的伪代码,您需要最后一个元素的md5总和:

paste -d ' '     \
  input_file.txt \
  <(cut -d' ' -f3 input_file.txt | parallel echo '{}' \| md5sum | cut -d' ' -f1) |
  awk '{ print $4, $3 > "file_1.txt"; print $1, $2, $4 > "file_2.txt" }'

解释

在进程替换中并行计算md5和,将此处的输出“粘贴”到原始文件上。最后,awk负责将输出放入正确的文件中。

修改

我同意 redShadow ,这在shell中永远不会非常有效,因为你需要 子壳很多。这是perl中的另一种选择:

split.pl

use Digest::MD5 qw(md5_hex);
use v5.10;

open O1, ">file_1.txt" or die $!; open O2, ">file_2.txt" or die $!;

$, = " ";

while(<>) { chomp; 
  @F = split / +/;
  $md5 = md5_hex $F[2];
  say O1 $md5, $F[2];
  say O2 @F[0,1], $md5;
}
close O1; close O2;

像这样跑:

<input_file.txt perl split.pl

两种情况下的输出:

file_1.txt

765ac5d0002aed1141a6a4e7b90e4ac9 1verylongalpha1234numeric1
b31901def07d436aed2c8028b2efa4ec 2verylongalpha1234numeric2
0722a6e50f6f8726f9754e7f71f9ad2c 3verylongalpha1234numeric3

file_2.txt

12347654 abcdfg 765ac5d0002aed1141a6a4e7b90e4ac9
34543673 nvjfur b31901def07d436aed2c8028b2efa4ec
75868643 vbdhde 0722a6e50f6f8726f9754e7f71f9ad2c