Executar um script em uma lista de arquivos
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
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
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
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