Eu tenho um script mycommand.sh
que não posso executar duas vezes. Desejo dividir a saída em dois arquivos diferentes, um arquivo contendo as linhas que correspondem a um regex e um arquivo contendo as linhas que não correspondem a um regex. O que eu gostaria de ter é basicamente algo assim:
./mycommand.sh | grep -E 'some|very*|cool[regex].here;)' --match file1.txt --not-match file2.txt
Eu sei que posso apenas redirecionar a saída para um arquivo e, em seguida, para dois greps diferentes com e sem a opção -v e redirecionar a saída para dois arquivos diferentes. Mas eu estava me perguntando se era possível fazer isso com um grep.
Então, é possível conseguir o que eu quero em uma única linha?
Há muitas maneiras de fazer isso.
Usando awk
O seguinte envia todas as linhas correspondentes
coolregex
ao file1. Todas as outras linhas vão para file2:Como funciona:
/[coolregex]/{print>"file1";next}
Quaisquer linhas correspondentes à expressão regular
coolregex
são impressas emfile1
. Em seguida, pulamos todos os comandos restantes e pulamos para recomeçar nanext
linha.1
Todas as outras linhas são enviadas para stdout.
1
é a abreviação enigmática do awk para imprimir a linha.A divisão em vários fluxos também é possível:
Usando substituição de processo
Isso não é tão elegante quanto a solução awk, mas, para completar, também podemos usar vários greps combinados com substituição de processo:
Também podemos dividir em vários fluxos:
w filename
- escreva o espaço do padrão atual no nome do arquivo.Se você deseja que todas as linhas correspondentes vão para
file_1
e todas as linhas não correspondentes parafile_2
, você pode fazer:ou
Explicação
/pattern/!{p;d};
/pattern/!
- negação - se uma linha não contémpattern
.p
- imprimir o espaço padrão atual.d
- excluir espaço padrão. Iniciar o próximo ciclo.file_2
no nosso caso. A próxima parte dosed
script (w file_1
) não é alcançada enquanto a linha não corresponde ao padrão.w file_1
- se uma linha contém padrão, a/pattern/!{p;d};
parte é pulada (porque só é executada quando o padrão não coincide) e, assim, esta linha vai para o arquivofile_1
.Gostei da
sed
solução, pois não depende de bashismos e trata os arquivos de saída da mesma forma. AFAIK, não existe uma ferramenta Unix autônoma que faça o que você deseja, então você precisa programá-la você mesmo. Se abandonássemos a abordagem do canivete suíço, poderíamos usar qualquer uma das linguagens de script (Perl, Python, NodeJS).É assim que seria feito no NodeJS
Exemplo de uso
Se você não se importa em usar Python e uma sintaxe de expressão regular diferente:
Uso
Exemplo