Boa maneira
Normalmente você não pode fazer isso com o grep, mas você pode usar outras ferramentas. O AWK já foi mencionado, mas você também pode usar sed
, assim:
sed -e '1p' -e '/youpattern/!d'
Como funciona:
-
O utilitário Sed funciona em cada linha individualmente, executando comandos especificados em cada um deles. Você pode ter vários comandos, especificando várias opções
-e
. Podemos prefixar cada comando com um parâmetro de intervalo que especifica se esse comando deve ser aplicado a uma linha específica ou não. -
"1p" é um primeiro comando. Ele usa o comando
p
, que normalmente imprime todas as linhas. Mas prefixamos com um valor numérico que especifica o intervalo ao qual ele deve ser aplicado. Aqui, usamos1
, o que significa primeira linha. Se você quiser imprimir mais linhas, poderá usarx,yp
, em quex
é a primeira linha a imprimir,y
é a última linha a ser impressa. Por exemplo, para imprimir as primeiras 3 linhas, você usaria1,3p
-
O próximo comando é
d
, o que normalmente exclui todas as linhas do buffer. Antes desse comando, colocamosyourpattern
entre dois caracteres/
. Essa é a outra maneira (primeiro era especificar quais linhas, como fizemos com o comandop
) das linhas de endereçamento nas quais o comando deveria estar rodando. Isso significa que o comando só funcionará para as linhas que correspondem ayourpattern
. Exceto, usamos o caractere!
antes do comandod
, que inverte sua lógica. Portanto, agora removerá todas as linhas que não correspondem ao padrão especificado. -
No final, o sed irá imprimir todas as linhas restantes no buffer. Mas removemos as linhas que não correspondem ao buffer, para que apenas as linhas correspondentes sejam impressas.
Para resumir: nós imprimimos a 1ª linha, então deletamos todas as linhas que não correspondem ao nosso padrão da entrada. Resto das linhas são impressas (portanto, apenas as linhas que fazem correspondem ao padrão).
Problema de primeira linha
Como mencionado nos comentários, há um problema com essa abordagem. Se o padrão especificado também corresponder à primeira linha, ele será impresso duas vezes (uma vez pelo comando p
e uma vez por causa de uma correspondência). Podemos evitar isso de duas maneiras:
-
Adicionando o comando
1d
após1p
. Como já mencionei, o comandod
exclui linhas do buffer e especificamos seu intervalo em número 1, o que significa que ele excluirá apenas a primeira linha. Então o comando seriased -e '1p' -e '1d' -e '/youpattern/!d'
-
Usando o comando
1b
, em vez de1p
. É um truque. O comandob
nos permite pular para outro comando especificado por um rótulo (dessa forma, alguns comandos podem ser omitidos). Mas se este rótulo não for especificado (como no nosso exemplo), ele simplesmente salta para o final dos comandos, ignorando o resto dos comandos para nossa linha. Portanto, no nosso caso, o último comandod
não removerá essa linha do buffer.
Exemplo completo:
ps aux | sed -e '1b' -e '/syslog/!d'
Usando ponto e vírgula
Algumas implementações de sed
podem economizar alguma digitação usando ponto-e-vírgula para separar comandos, em vez de usar várias opções de -e
. Então, se você não se importa em ser portátil, o comando seria ps aux | sed '1b;/syslog/!d'
. Ele funciona pelo menos em GNU sed
e busybox
implementações.
caminho louco
Aqui está, no entanto, uma maneira meio louca de fazer isso com o grep. Definitivamente não é ideal, estou postando isso apenas para fins de aprendizado, mas você pode usá-lo, por exemplo, se você não tiver outra ferramenta em seu sistema:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'
Como funciona
-
Primeiro, usamos a opção
-n
para adicionar números de linha antes de cada linha. Queremos numerar todas as linhas que estamos correspondendo.*
- qualquer coisa, até mesmo linha vazia. Como sugerido nos comentários, também podemos combinar '^', o resultado é o mesmo. -
Em seguida, estamos usando expressões regulares estendidas para que possamos usar o caractere especial
\|
, que funciona como OU. Então, combinamos se a linha começa com1:
(primeira linha) ou contém nosso padrão (neste caso, seusyslog
).
Problema de números de linha
Agora, o problema é que estamos obtendo esses números de linha feios em nossa saída. Se isso for um problema, podemos removê-los com cut
, assim:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-
A opção -d
especifica o delimitador, -f
especifica os campos (ou colunas) que queremos imprimir. Portanto, queremos cortar cada linha em cada caractere :
e imprimir apenas a segunda e todas as colunas subseqüentes. Isso efetivamente remove a primeira coluna com seu delimitador e é exatamente disso que precisamos.