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 asometext
ousomeothertext
ousomedifferenttext
. 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 (awkprint
call 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,!,