我有一个myfile.txt
包含多种记录类型的。
记录类型位于位置27,长度为3个字符,如下所示:
12345678901234567890123456E20XXXXXXXXX
12345678901234567890123456I47XXXXXXXXX
12345678901234567890123456I49XXXXXXXXX
12345678901234567890123456I50XXXXXXXXX
12345678901234567890123456W55XXXXXXXXX
12345678901234567890123456E20XXXXXXXXX
12345678901234567890123456I47XXXXXXXXX
12345678901234567890123456Q11XXXXXXXXX
12345678901234567890123456R11XXXXXXXXX
12345678901234567890123456W55XXXXXXXXX
12345678901234567890123456E20XXXXXXXXX
12345678901234567890123456I47XXXXXXXXX
12345678901234567890123456I49XXXXXXXXX
12345678901234567890123456I50XXXXXXXXX
12345678901234567890123456Q11XXXXXXXXX
12345678901234567890123456R11XXXXXXXXX
12345678901234567890123456W55XXXXXXXXX
我想按记录类型拆分它,如下所示:
grep -E '^.{26}(E20)' myfile.txt > E20.txt
grep -E '^.{26}(I47)' myfile.txt > I47.txt
grep -E '^.{26}(I49)' myfile.txt > I49.txt
grep -E '^.{26}(I50)' myfile.txt > I50.txt
grep -E '^.{26}(Q11)' myfile.txt > Q11.txt
grep -E '^.{26}(R11)' myfile.txt > R11.txt
grep -E '^.{26}(W55)' myfile.txt > W55.txt
并做其他事情,例如
echo "Unexpected record type"
当记录类型不是(E20、I47、I49、I50、Q11、R11、W55)时。
例如,E20.txt
文件将是:
12345678901234567890123456E20XXXXXXXXX
12345678901234567890123456E20XXXXXXXXX
12345678901234567890123456E20XXXXXXXXX
等等。
在 Linux 上有没有一种优雅的方法(在脚本中)做到这一点?
答案1
这是一种awk
方法。首先,创建一个包含“良好”记录的文件,每行一个:
$ cat goodRecs
E20
I47
I49
I50
Q11
R11
W55
然后:
gawk 'FNR==NR{good[$1]; next}
{
rec=substr($1,27,3);
if(rec in good){
print > rec".txt"
}
else{
print "Bad record: "rec
}
}' goodRecs myfile.txt
答案2
使用任何 awk 和任何排序:
$ cat tst.sh
#!/usr/bin/env bash
awk '
BEGIN {
split("E20 I47 I49 I50 Q11 R11 W55",tmp)
for ( i in tmp ) {
expected[tmp[i]]
}
}
{
type = substr($0,27,3)
if ( type in expected ) {
print type, NR, $0
}
else {
printf "%s[%d]: Unexpected record type \"%s\"\n", FILENAME, FNR, type | "cat>&2"
}
}
' "${@:--}" |
sort -k1,1 -k2,2n |
awk '
$1 != prev {
close(out)
out = $1 ".txt"
prev = $1
}
{ print $3 > out }
'
$ ./tst.sh myfile.txt
$ head [A-Z]*.txt
==> E20.txt <==
12345678901234567890123456E20XXXXXXXXX
12345678901234567890123456E20XXXXXXXXX
12345678901234567890123456E20XXXXXXXXX
==> I47.txt <==
12345678901234567890123456I47XXXXXXXXX
12345678901234567890123456I47XXXXXXXXX
12345678901234567890123456I47XXXXXXXXX
==> I49.txt <==
12345678901234567890123456I49XXXXXXXXX
12345678901234567890123456I49XXXXXXXXX
==> I50.txt <==
12345678901234567890123456I50XXXXXXXXX
12345678901234567890123456I50XXXXXXXXX
==> Q11.txt <==
12345678901234567890123456Q11XXXXXXXXX
12345678901234567890123456Q11XXXXXXXXX
==> R11.txt <==
12345678901234567890123456R11XXXXXXXXX
12345678901234567890123456R11XXXXXXXXX
==> W55.txt <==
12345678901234567890123456W55XXXXXXXXX
12345678901234567890123456W55XXXXXXXXX
12345678901234567890123456W55XXXXXXXXX
上面使用的是DSU(装饰/排序/取消装饰)习惯用法使脚本非常高效、健壮和可移植,同时保留重复键的输入顺序。
答案3
bash(或 POSIX shell)版本
#! /bin/sh
exec < "$1"
while read aline
do key=${aline:26:3}
case $key in
E20|I47|I49|I50|Q11|R11|W55)
echo $aline >> $key.txt;;
*) echo "${0##/} Unexpected record '$key' encounterd" 1>&2;;
esac
done
运行此命令:
sh program-name input-file-name
如果 /bin/sh 不可用,请使用 bash。