OK, antes de tudo, não use um loop for ! Isso é muito ineficiente. Apenas dê grep todos os nomes de arquivos de uma só vez:
grep 'sometext:' folder/*.txt
Nesse caso, no entanto, usaria awk em vez de grep . Eu fiz 10 cópias do seu arquivo de entrada para testar:
$ awk '{
if($1~/sometext|someothertext|somedifferenttext/){
printf "%s,",$2
}
if(FNR==1 && NR>1){
print ""
}
}
END{ print "" }' folder/*txt
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Explicação
awk é uma linguagem de script que lê sua linha de entrada por linha e divide cada linha no espaço em branco (por padrão, você pode alterar isso com -F ) em campos. O primeiro campo será $1 , o segundo $2 etc.
-
if($1~/sometext|someothertext|somedifferenttext/){: se o primeiro campo corresponder asometextousomeothertextousomedifferenttext. Observe que isso também corresponderá afoosometext. Se você quiser limitar as correspondências exatas, altere para:if($1=="sometext:" || $1=="someothertext:" || $1=="somedifferenttext:"){ -
printf "%s,",$2: se a condição acima for atendida, imprima o 2º campo seguido por uma vírgula. -
if(FNR==1 && NR>1){ print "" }:NRé o número da linha de entrada atual eFNRé o número da linha do arquivo atual. Portanto, imprima uma nova linha (awkprintcall adiciona uma nova linha por padrão, portanto, imprimir nada é como imprimir uma nova linha) sempre que o número da linha do arquivo for 1, mas não se o número total de linhas processadas também for um. Em outras palavras, imprima uma nova linha toda vez que começarmos a ler um novo arquivo. -
END{ print "" }': imprima também uma nova linha depois de processar todos os arquivos.
Observe que isso pressupõe que você tenha apenas 2 campos por linha. Se você precisar imprimir toda a linha, poderá usar (usando a versão que imprime apenas correspondências exatas para ilustrar):
awk '{
if($1=="sometext:" ||
$1=="someothertext:" ||
$1=="somedifferenttext:"){
$1="";
printf "%s,",$0
}
if(FNR==1 && NR>1){print ""}
}END{print ""}' folder/*txt | sed 's/^ //'
A diferença é que usamos $0 (a linha completa) em vez de $2 e definimos $1 na cadeia vazia antes da impressão. Isso resulta em um espaço extra impresso no início (porque o $1 vazio ainda é considerado um campo), então passamos por sed para removê-lo.
Alternativamente, você também pode fazer tudo em Perl:
$ perl -lane '
if($F[0]=~/(sometext|someothertext|somedifferenttext):/){
push @k,@F[1..$#F]
}
if(eof){
print join ",", @k; @k=();
}' folder/file*
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Ou também para ter o , :
$ perl -lane '
if($F[0]=~/^(sometext|someothertext|somedifferenttext):$/){
push @k,@F[1..$#F]
}
if(eof){
print join ",", @k , ""; @k=();
}' folder/file*
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Explicação
A ideia básica aqui é a mesma. A opção -a do Perl faz com que ela se comporte como awk , dividindo cada linha de entrada na matriz @F . Então, se o primeiro elemento da matriz for uma das strings desejadas, o restante dos campos ( @F[1..$#F] ) serão adicionados à matriz @k . Se chegarmos ao final de um arquivo ( if(eof) ), juntamos o conteúdo do array @k com vírgulas e imprimimos a string resultante.
Finalmente, aqui está uma maneira de fazer isso da maneira que você estava tentando (assumindo o GNU grep ):
$ for f in folder/*; do
grep -hoP '^(sometext|someothertext|somedifferenttext): \K.*' "$f" |
perl -pe 's/\n/,/; END{print "\n"}';
done
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,