Esecuzione di uno script su un elenco di file

Aug 23 2020

Ho uno script che ottiene un file .vcf, lo analizza e lo scrive in .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

Ho 27 .vcffile su cui voglio eseguire questo script contemporaneamente e scrivere l'output di ciascuno .vcfin un .txtfile con il nome di quello.vcf

L'ho trovato in google ma non succede nulla dopo averlo eseguito

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

L'ho adottato come di seguito

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

Ho provato anche quello

(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$ 

Come posso fare in modo che funzioni per me?

Risposte

EdMorton Aug 23 2020 at 20:05

Hai convertito script "$f"l'output di Google in grep -v "#"(cioè manca il "$f") nello script del ciclo di shell e quindi lo stai usando "$f"invece di {}e lo stai usando nel posto sbagliato nel tuo xargsscript.

Comunque non hai mai bisogno di un mucchio di sed e greps in una pipleine quando usi awk comunque. Non hai fornito alcun input / output di esempio, quindi il seguente script awk è solo una traduzione diretta della tua pipeline esistente e probabilmente c'è un modo migliore per scriverlo, ma questo script awk è tutto ciò di cui hai bisogno, nessun ciclo di shell o altro :

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 vuoi riempirlo su meno righe come hai fatto con la tua pipeline grep + seds + awk puoi semplicemente usare i punti e virgola ovunque ci sia una nuova riga di cui vuoi sbarazzarti tranne dopo ciascuna {, ad esempio:

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

Puoi usare find e xargs per questo.

Trova elencherà tutti i file.

find -type f -name "*.vcf"

Con xargs possiamo operare su ogni file che è stato trovato.

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"

dovrebbe fare il lavoro?

saluti

RakeshSharma Aug 23 2020 at 13:42

Senza alterare il flusso, quanto segue dovrebbe funzionare. Nota che non stavi immettendo nulla al primo comando grep nella pipeline. Quindi niente si muoveva.

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