web-dev-qa-db-ja.com

列を置き換えて間隔を維持する

これは unixのフォローアップです:1つのファイルの1つの列全体を別のファイルの1つの値に置き換えます

ファイルの1つの列(file1)を別のファイル(file2)の特定の値に置き換えようとしています。

file1は次のように構成されています。

HETATM    8  P   FAD B 600      98.424  46.244  76.016  1.00 18.65
HETATM    9  O1P FAD B 600      98.634  44.801  75.700  1.00 17.69 O  
HETATM   10  O2P FAD B 600      98.010  46.640  77.387  1.00 15.59 O  
HETATM   11 H5B1 FAD B 600      96.970  48.950  72.795  1.00 -1.00 H  

そして私は絶対にその構造を保存する必要があります。

file2は次のように構成されています。

1 27, -81.883, 4.0
5 48, -67.737, 20.0
1 55, -72.923, 4.0
4 27, -62.64, 16.0

Awkが「誤動作」していて、pdbファイルの形式が失われていることに気付きました。つまり、次の代わりに次のことを意味します。

HETATM    1  PA  FAD B 600      95.987  47.188  74.293  1.00 -73.248

私は得る

HETATM 1 PA FAD B 600 95.887 47.194 74.387 1.00 -73.248 

私が試してみました:

file1="./Min1_1.traj_COP1A_.27.pdb"
file2="./COP1A_report1"
value="$(awk -F, 'NR==1{print $2;exit}' $file2)"
#option 1: replaces the column I want but messes up the format
awk -F ' ' '{$11 = v} 1' v="$value" $file1 >TEST1
#option 2: keeps the format but adds the value at the end only
awk -F ' ', '{$2 = v} 1' v="$value" $file1 >TEST2
awk -F, '{$11 = v} 1' v="$value" $file1 >TEST3

これは、pdbファイルのすべての列に同じ区切り文字がなく、awkが希望する方法でそれを処理していないためだと思います。

この問題に対してawkを「飼いならす」方法や、他にどのようなコマンドを使用するかについてのアイデアはありますか?

3
gugy

正規表現([^[:blank:]]、つまり空白以外)を使用し、11番目の一致を置き換えます。

awk '{print gensub (/[^[:blank:]]+/, v, 11)}' v="$value" infile

sedと同じ:

sed "s/[^[:blank:]]\{1,\}/${value}/11" infile

別の方法として、ファイルに固定長のフィールドがあり、各フィールドの「位置」がわかっている場合(たとえば、サンプルファイル内のスペースのみを想定すると、11番目のフィールドは各行の57番目から60番目までの4文字を占めます)

awk '{print substr($0,1,56) v substr($0,61)}' v=$value file

または

sed -E "s/^(.{56}).{4}(.*)$/\1${value}\2/" infile
4
don_crissti

私はあなたの仕事にsedを使うことを提案します:

file1="./Min1_1.traj_COP1A_.27.pdb"
file2="./COP1A_report1"
IFS=',' read -r a value b <"$file2"
#for second field:
sed "s/.[0-9]\b/$value/" "$file1" > TEST1
#for 11th field:
sed "s/\S.\.[0-9]\{2\}\b/$value/" "$file1" > TEST1
1
Costas

GAWK 4では、文字列(または行全体)を明示的に分割し、分割の結果(フィールドとセパレーター)を反復して出力することにより、フィールドセパレーターを保持できます。

この例では、FPAT(フィールド構造を指定する正規表現)とpatsplit()を使用しますが、FS(フィールド区切り文字を指定する正規表現、または[ \t\n]+を表す単一のスペースを含む正規表現)を使用できます。代わりにsplit()

gawk "v=$value" '{n = patsplit($0, arr, FPAT, seps); arr[11] = v; for (i = 0; i <= n; i++) {printf "%s%s", a[i], seps[i]}; print ""}'

a[0]は常にnullになり、seps[0]には先頭の区切り文字が含まれ、seps[n]は入力行の終わりにある区切り文字(空白)になることに注意してください。

これは、より読みやすい形式のワンライナーです。

gawk "v=$value" '
    {
        n = patsplit($0, arr, FPAT, seps); 
        arr[11] = v; 
        for (i = 0; i <= n; i++) {
            printf "%s%s", a[i], seps[i]
        }; 
        print ""
    }'