/ / Como posso usar o sed para fazer milhares de substituições em um arquivo usando um arquivo de referência? - banco de dados, bash, dicionário, awk, sed

Como posso usar o sed para fazer milhares de substituições em um arquivo usando um arquivo de referência? - banco de dados, bash, dicionário, awk, sed

Eu tenho um grande arquivo com duas colunas como esta:

 tiago@tiago:~/$ head Ids.txt
TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6
TRINITY_DN126999_c0_g1_i1 ENSMUST00000040656.6
TRINITY_DN126906_c0_g1_i1 ENSMUST00000126770.1
TRINITY_DN126907_c0_g1_i1 ENSMUST00000192613.1
TRINITY_DN126988_c0_g1_i1 ENSMUST00000032372.6
.....

e eu tenho outro arquivo com dados, como este:

"baseMean" "log2FoldChange" "lfcSE" "stat" "pvalue" "padj" "super" "sub" "threshold"
"TRINITY_DN41319_c0_g1" 178.721774751278 2.1974294626636 0.342621318593487 6.41358066008381 1.4214085388179e-10 5.54686423073089e-08 TRUE FALSE "TRUE"
"TRINITY_DN87368_c0_g1" 4172.76139849472 2.45766387851112 0.404014016558211 6.08311538160958 1.17869459181235e-09 4.02673069375893e-07 TRUE FALSE "TRUE"
"TRINITY_DN34622_c0_g1" 39.1949851245197 3.28758092748061 0.54255370348027 6.05945716781964 1.3658169042862e-09 4.62597265729593e-07 TRUE FALSE "TRUE"
.....

Estava pensando em usar o sed para fazer uma tradução dos valores da primeira coluna do arquivo de dados, usando o primeiro arquivo como dicionário.

Ou seja, considerando cada linha do arquivo de dadospor sua vez, se o valor da primeira coluna corresponder a um valor da primeira coluna do arquivo de dicionário, será feita uma substituição; caso contrário, a linha seria simplesmente impressa.

Qualquer sugestão seria apreciada.

Respostas:

1 para resposta № 1

Você pode transformar seu primeiro arquivo Ids.txt em um script sed:

$ sed -r "s| *(S+) (S+)|s/^"1/"2/|" Ids.txt > repl.sed
$ cat repl.sed
s/^"TRINITY_DN126999_c0_g1_i1/"ENSMUST00000040656.6/
s/^"TRINITY_DN126999_c0_g1_i1/"ENSMUST00000040656.6/
s/^"TRINITY_DN126906_c0_g1_i1/"ENSMUST00000126770.1/
s/^"TRINITY_DN126907_c0_g1_i1/"ENSMUST00000192613.1/
s/^"TRINITY_DN126988_c0_g1_i1/"ENSMUST00000032372.6/

Isso remove os espaços iniciais e transforma cada linha em um comando de substituição.

Em seguida, você pode usar este script para fazer as substituições em seu arquivo de dados:

sed -f repl.sed datafile

... com redirecionamento para outro arquivo, ou no local com sed -i.

Se você não tem GNU sed, você pode usar esta versão compatível com POSIX do primeiro comando:

sed "s| *([^ ]*) ([^ ]*)|s/^"1/"2/|" Ids.txt

Isso usa expressões regulares básicas em vez de estendidas e usa [^ ] para "não espaço" em vez de S.


1 para resposta № 2

Como o primeiro arquivo (o arquivo de dicionário) é grande, usando sed pode ser muito lento; uma abordagem muito mais rápida e não muito mais complexa seria usar awk do seguinte modo:

awk -v col=1 -v dict=Ids.txt "
BEGIN {while(getline<dict){a["""$1"""]="""$2"""} }
$col in a {$col=a[$col]}; {print}"

(Aqui, "Ids.txt" é o arquivo de dicionário e "col" é o número da coluna do campo de interesse no arquivo de dados.)

Essa abordagem também tem a vantagem de não exigir nenhuma modificação no arquivo de dicionário.


0 para resposta № 3
#!/bin/bash

# Declare hash table
declare -A Ids

# Go though first input file and add key-value pairs to hash table
while read Id; do
key=$(echo $Id | cut -d " " -f1)
value=$(echo $Id | cut -d " " -f2)
Ids+=([$key]=$value)
done < $1

# Go through second input file and replace every first column with
# the corresponding value in the hash table if it exists
while read line; do
first_col=$(echo $line | cut -d """ -f2)
new_id=${Ids[$first_col]}

if [ -n "$new_id" ]; then
sed -i s/$first_col/$new_id/g $2
fi
done < $2

Eu chamaria o script de

./script.sh Ids.txt data.txt