Executando comandos em vários arquivos e dando a cada saída um nome exclusivo

1

Eu quero executar um script em todos os arquivos em uma pasta como esta:

sh script.sh *.fasta > output

no entanto, quero que as saídas estejam em arquivos individuais para cada entrada. Então, ao invés de obter 5 arquivos através do comando e colocá-los todos em um arquivo chamado "output", existe uma maneira de ter as saídas como o nome do arquivo com um sufixo no final, como "_output"?

Então, se eu tivesse 3 arquivos como:

file1.fasta
file2.fasta
file3.fasta

Existe uma maneira de executar um comando como este:

sh script.sh *.fasta

e imprime os novos arquivos como este para cada entrada:

file1_new.fasta
file2_new.fasta
file3_new.fasta

Eu tentei o comando:

sh script.sh *.fasta > *_output.fasta

Mas isso não funcionou, eu também tentei atribuir todos os arquivos de interesse a uma variável como essa, com a idéia de que talvez eu pudesse renomear as saídas se as atribuísse pela primeira vez a uma variável:

allthefiles= *.fasta

Mas isso também não funcionou. Eu não sei como chamar essa pergunta, desculpe se já foi perguntado! Como executo vários arquivos por meio de um comando e tenho uma nova saída para cada entrada?

    
por kevluv93 23.03.2016 / 21:45

5 respostas

1

Shell normal, dentro de um script ou função:

for file in "$@" ; do
  if true; do 
     # do some work which reads from stdin
     # and outputs to stdout
  fi > "${file}_output.fasta" < "$file"
done

Ou o mais convencional (mas possivelmente tedioso)

for file in "$@" ; do
  output="${file}_output.fasta"
  some_program $file > $output
  another_program_appends $file >> $output
done

Você também pode fazer algo assim com o awk:

$ awk '{ print substr($0,1,20) >> FILENAME "_output.fasta" }' *fasta

O script awk gera os primeiros 20 caracteres de cada linha de cada arquivo de entrada, salvando a saída como esperado.

    
por 23.03.2016 / 21:58
2
for f in *.fasta; do 
    sh script.sh "$f" > "${f%.*}_output.fasta"; 
done

# ${f%.*} strips a shortest match of '.*' from the end of "$f"
# (= strips .fasta)
    
por 23.03.2016 / 22:06
2

Use make !

Escreva um arquivo chamado GNUmakefile com o conteúdo abaixo, mas onde eu coloquei o caractere ↦, coloque uma aba no lugar (tem que ser uma aba, não pode ser espaços).

all: $(filter-out %_output.fasta,$(wildcard *.fasta))

%_output.fasta: %.fasta
↦./script.sh $< >[email protected]
↦mv [email protected] $@

Agora, para gerar todos os arquivos, digite make . Como bônus, se um arquivo de entrada não tiver sido alterado desde que o arquivo de saída foi gerado pela última vez, script.sh não será executado novamente. Se você estiver modificando ativamente script.sh e desejar gerar novamente os arquivos de saída, adicione script.sh após %.fasta , dessa forma os arquivos também serão regenerados se o script for alterado.

Explicações:

  • A primeira linha especifica o que fazer quando você executa make all . Como é a primeira linha (o primeiro target , na terminologia do makefile), executar make sem argumento faz a mesma coisa.
  • A parte depois de all: gera a lista de nomes de .fasta arquivos no diretório atual e remove os chamados _output.fasta .
  • A linha %_output.fasta: %.fasta inicia uma regra que explica como gerar um arquivo cujo nome termina com _output.fasta (o destino ) do arquivo .fasta correspondente (uma dependência ).
  • As seguintes linhas recuadas por guias são os comandos a serem executados para gerar os arquivos.
  • A primeira linha transforma a primeira dependência ( $< ) em um arquivo .tmp .
  • A segunda linha renomeia o arquivo .tmp para o arquivo de destino ( $@ ). O motivo desse processo de duas etapas é que, se a geração for interrompida por algum motivo, isso não deixará um arquivo de destino inválido.

Nota: suponho que você esteja usando o Linux. Caso contrário, pode ser necessário instalar o GNU make e executá-lo em vez do comando make padrão do seu sistema, se você quiser usar o código acima.

Se você usou uma extensão diferente para os arquivos de saída, isso tornaria as coisas um pouco mais fáceis.

all: $(patsubst %.fasta,%.out,$(wildcard *.fasta))

.SUFFIX: .out .fasta
.fast.out:
↦./script.sh $< >[email protected]
↦mv [email protected] $@

Se você substituir a primeira linha pela lista explícita de arquivos ( all: foo.out bar.out ), o arquivo poderá ser chamado de Makefile e será executado com qualquer implementação de make .

    
por 24.03.2016 / 01:02
1

Aqui está uma solução de uma linha

find ./ -name "*.fasta" -exec sh -c 'script.sh ${0} > ${0}.log' {} \;

Em suma, ele encontra os arquivos que você quer e executa o seu script neles. O ponto de usar sh -c é para que o caractere de redirecionamento > não seja interpretado diretamente.

    
por 23.03.2016 / 22:01
1

Você pode fazê-los em paralelo com ... gnu paralelo:

parallel "sh script.sh {} > {}.out" ::: *
    
por 24.03.2016 / 01:21