Substituir uma coluna e preservar o espaçamento

2

Este é um acompanhamento para unix: substitua uma coluna inteira em um arquivo por um único valor de outro arquivo

Eu estou tentando substituir uma coluna de um arquivo (arquivo1) por um valor específico de outro arquivo (arquivo2).

file1 é estruturado assim:

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  

e eu absolutamente preciso conservar essa estrutura.

o arquivo2 é estruturado assim:

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

Percebi que o awk está "se comportando mal" e perde o formato do meu arquivo pdb, o que significa que, em vez de:

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

Eu obtenho

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

Eu tentei:

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

Eu acho que é porque um arquivo pdb não tem os mesmos delimitadores para todas as colunas e o awk não está lidando com isso da maneira que eu quero.

Alguma idéia de como "domar" o awk para esse problema ou que outro comando usar?

    
por gugy 28.10.2015 / 15:03

3 respostas

4

Use um regex ( [^[:blank:]] ou seja, não em branco) e substitua a correspondência 11 th:

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

Mesmo com sed :

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

Outra forma, se o seu arquivo tiver campos de tamanho fixo e você souber a "posição" de cada campo (por exemplo, assumindo apenas espaços no arquivo de amostra, o 11º campo ocupa 4 caracteres, de 57º a 60º em cada linha)

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

ou

sed -E "s/^(.{56}).{4}(.*)$/${value}/" infile
    
por 28.10.2015 / 15:46
1

Eu me ofereceria para usar sed para sua tarefa:

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
    
por 28.10.2015 / 16:46
1

Com o GAWK 4, você pode preservar os separadores de campo dividindo explicitamente uma string (ou a linha inteira) e iterando sobre o resultado da divisão (campos e separadores) para saída.

Este exemplo usa FPAT (um regex especificando a estrutura do campo) e patsplit() , mas poderia usar FS (um regex especificando o separador de campo ou contendo um único espaço para representar [ \t\n]+ ) e 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 ""}'

Observe que a[0] será sempre nulo, seps[0] conterá qualquer separador inicial e seps[n] será qualquer caractere separador (espaço em branco) no final da linha de entrada. '

Aqui está o oneliner de uma forma mais legível:

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 ""
    }'
    
por 28.10.2015 / 22:00