レコードタイプ別にレコードを分割し、予期しないレコードタイプを報告します。

レコードタイプ別にレコードを分割し、予期しないレコードタイプを報告します。

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方法です。まず、「良い」レコードが1行に1つずつ含まれるファイルを作成します。

$ 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シェル)バージョン

#! /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 を使用してください。

関連情報