Executar um script em uma lista de arquivos

Aug 23 2020

Eu tenho um script que obtém um arquivo .vcf, analisa e grava em um .txt

grep -v "#" file.vcf | sed 's/chrM/MT/' | sed 's/chrX/X/' | sed 's/chrY/Y/' | awk '{print $1,$2,$2,$4"/"$5,"+"}' | sed 's/chr//g' > vcf_output.txt

Eu tenho 27 .vcfarquivos nos quais desejo executar este script ao mesmo tempo e escrever a saída de cada .vcfum em um .txtarquivo com o nome daquele.vcf

Eu encontrei isso no google, mas nada acontece depois de executar isso

for f in *.vcf; do
    script "$f" > "${f%.*}.txt"
done

Eu adotei assim abaixo

for f in *.vcf; do

grep -v "#" | sed 's/chrM/MT/' | sed 's/chrX/X/' | sed 's/chrY/Y/' | awk '{print $1,$2,$2,$4"/"$5,"+"}' | sed 's/chr//g' "$f" > "${f%.*}.txt"
    done

Eu também tentei isso

(base) loan-mac-13:Pre_Treatment fi1d18$ find -type f -name "*.vcf" | xargs grep -v "#" | sed 's/chrM/MT/' | sed 's/chrX/X/' | sed 's/chrY/Y/' | awk '{print $1,$2,$2,$4"/"$5,"+"}' | sed 's/chr//g' "$f" > "${f%.*}.txt"
find: illegal option -- t
usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]
       find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]
sed: : No such file or directory
(base) loan-mac-13:Pre_Treatment fi1d18$ 

Como posso fazer isso funcionar para mim?

Respostas

EdMorton Aug 23 2020 at 20:05

Você converteu script "$f"sua saída do Google em grep -v "#"(ou seja, sem o "$f") em seu script de loop de shell e, em seguida, está usando em "$f"vez de {}e usando-o no lugar errado em seu xargsscript.

Você nunca precisa de um monte de seds e greps em um pipleine quando está usando awk de qualquer maneira. Você não forneceu nenhuma entrada / saída de amostra, então o seguinte script awk é apenas uma tradução direta de seu pipeline existente e provavelmente há uma maneira melhor de escrevê-lo, mas este script awk é tudo que você precisa, sem loops de shell ou qualquer outra coisa :

awk '
    FNR == 1 {
        close(out)
        out = FILENAME
        sub(/\.vcf$/,".txt",out)
    }
    !/#/ {
        sub(/chrM/,"MT")
        sub(/chrX/,"X")
        sub(/chrY/,"Y")
        $0 = $1 OFS $2 OFS $2 OFS $4 "/" $5 OFS "+"
        gsub(/chr/,"")
        print > out
    }
' *.vcf

Se você quiser empilhá-lo em menos linhas como fez com o pipeline grep + seds + awk, você pode simplesmente usar ponto-e-vírgula em todos os lugares onde houver uma nova linha da qual deseja se livrar, exceto após cada um {, por exemplo:

awk 'FNR==1{close(out); out=FILENAME; sub(/\.vcf$/,".txt",out)} !/#/{sub(/chrM/,"MT"); sub(/chrX/,"X"); sub(/chrY/,"Y"); $0=$1 OFS $2 OFS $2 OFS $4 "/" $5 OFS "+"; gsub(/chr/,""); print > out}' *.vcf
xddq Aug 23 2020 at 08:48

Você pode usar find e xargs para isso.

Localizar listará todos os arquivos.

find -type f -name "*.vcf"

Com o xargs, podemos operar em todos os arquivos encontrados.

find -type f -name "*.vcf" | xargs grep -v "#" | sed 's/chrM/MT/' | sed 's/chrX/X/' | sed 's/chrY/Y/' | awk '{print $1,$2,$2,$4"/"$5,"+"}' | sed 's/chr//g' "$f" > "${f%.*}.txt"

deve fazer o trabalho?

saudações

RakeshSharma Aug 23 2020 at 13:42

Sem alterar nada do seu fluxo, o seguinte deve funcionar. Observe que você não estava inserindo nada no primeiro comando grep no pipeline. Portanto, nada estava se movendo.

for f in *.vcf; do

< "$f"  grep -v "#" | sed 's/chrM/MT/' | sed 's/chrX/X/' | sed 's/chrY/Y/' | awk '{print $1,$2,$2,$4"/"$5,"+"}' | sed 's/chr//g'  > "${f%.*}.txt"
    done