Supondo um grep simples como:
$ psa aux | grep someApp
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
Isso fornece muita informação, mas como a primeira linha do comando ps está ausente, não há contexto para a informação. Eu preferiria que a primeira linha do ps seja mostrada também:
$ psa aux | someMagic someApp
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
Obviamente, eu poderia adicionar um regex ao grep especificamente para ps:
$ ps aux | grep -E "COMMAND|someApp"
No entanto, eu preferiria uma solução mais geral, pois há outros casos em que gostaria de ter a primeira linha também.
Parece que este seria um bom caso de uso para um descritor de arquivo "stdmeta" .
bash
command-line
dotancohen
fonte
fonte
ack
são tão úteis, e por queperl
passado disparoused
,awk
etc. em popularidade: é importante para as partes para resumir em um todo coerente.-C
argumentops
e não precisará canalizá-lo para o grep. por exemplo,ps u -C someApp
ou mesmops u -C app1 -C app2 -C app3
ps aux | { head -1; grep foo; }
mencionada por @Nahuel FOUILLEUL abaixo (o seu é provavelmente a única solução que eu seria capaz de recordar no local, se necessário)Respostas:
Bom caminho
Normalmente você não pode fazer isso com o grep, mas pode usar outras ferramentas. O AWK já foi mencionado, mas você também pode usar o
sed
seguinte:Como funciona:
O utilitário Sed trabalha em cada linha individualmente, executando comandos especificados em cada uma delas. Você pode ter vários comandos, especificando várias
-e
opções. Podemos acrescentar cada comando com um parâmetro range que especifica se esse comando deve ser aplicado a uma linha específica ou não."1p" é o primeiro comando. Ele usa o
p
comando que normalmente imprime todas as linhas. Mas o anexamos com um valor numérico que especifica o intervalo ao qual ele deve ser aplicado. Aqui, usamos o1
que significa primeira linha. Se você quiser imprimir mais linhas, poderá usarx,yp
ondex
está a primeira linha a ser impressa, ay
última linha a ser impressa. Por exemplo, para imprimir as 3 primeiras linhas, você usaria1,3p
O próximo comando é o
d
que normalmente exclui todas as linhas do buffer. Antes deste comando, colocamosyourpattern
entre dois/
caracteres. Essa é a outra maneira (primeiro foi especificar em quais linhas, como fizemos com op
comando), de endereçar as linhas nas quais o comando deve estar em execução. Isso significa que o comando funcionará apenas para as linhas correspondentesyourpattern
. Exceto, usamos!
caractere antes dod
comando que inverte sua lógica. Portanto, agora ele removerá todas as linhas que não correspondem ao padrão especificado.No final, o sed 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.
Resumindo: imprimimos a primeira linha e excluímos todas as linhas que não correspondem ao nosso padrão da entrada. Resto das linhas são impressos (para que apenas as linhas que fazem corresponder ao padrão).
Problema de primeira linha
Como mencionado nos comentários, há um problema com essa abordagem. Se o padrão especificado corresponder também à primeira linha, ele será impresso duas vezes (uma vez por
p
comando e uma vez por causa de uma correspondência). Podemos evitar isso de duas maneiras:Adicionando
1d
comando depois1p
. Como já mencionei, od
comando exclui as linhas do buffer e especificamos seu intervalo pelo 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
1b
comando, em vez de1p
. É um truque.b
O comando nos permite pular para outro comando especificado por um rótulo (dessa maneira, alguns comandos podem ser omitidos). Mas se esse rótulo não for especificado (como no nosso exemplo), ele simplesmente pula para o final dos comandos, ignorando o restante dos comandos da nossa linha. Portanto, no nosso caso, o últimod
comando não removerá essa linha do buffer.Exemplo completo:
Usando ponto e vírgula
Algumas
sed
implementações podem economizar digitação usando ponto-e-vírgula para separar comandos, em vez de usar várias-e
opções. Portanto, se você não se importa em ser portátil, o comando seriaps aux | sed '1b;/syslog/!d'
. Funciona pelo menos emGNU sed
ebusybox
implementações.Maneira louca
Aqui está, no entanto, uma maneira bastante louca de fazer isso com o grep. Definitivamente não é o ideal, estou publicando isso apenas para fins de aprendizado, mas você pode usá-lo, por exemplo, se não tiver nenhuma outra ferramenta no seu sistema:
Como funciona
Primeiro, usamos a
-n
opção para adicionar números de linha antes de cada linha. Queremos numerar todas as linhas com as quais estamos combinando.*
- qualquer coisa, até a linha vazia. Como sugerido nos comentários, também podemos combinar '^', o resultado é o mesmo.Então, estamos usando expressões regulares estendidas para que possamos usar
\|
caracteres especiais que funcionam como OR. Então, combinamos se a linha começa com1:
(primeira linha) ou contém nosso padrão (nesse caso, ésyslog
).Problema de números de linha
Agora, o problema é que estamos obtendo esses números de linha feios em nossa saída. Se este for um problema, podemos removê-los com
cut
, desta forma:-d
opção especifica delimitador,-f
especifica campos (ou colunas) que queremos imprimir. Portanto, queremos cortar cada linha de cada:
caractere e imprimir apenas a segunda e todas as colunas subseqüentes. Isso efetivamente remove a primeira coluna com seu delimitador e é exatamente isso que precisamos.fonte
cat -n
e pareceria mais clara, com um grep abusado por isso.nl
não conta linhas vazias (mas as imprime sem número de linha),cat -n
formata a numeração com espaços anteriores,grep -n .
retira as linhas vazias e adiciona dois pontos. Todos têm os seus ... er ... características ;-)ps aux | sed '1p;/pattern/!d'
imprimirá a primeira linha duas vezes se corresponder ao padrão . Melhor é utilizado ob
comando:ps aux | sed -e 1b -e '/pattern/!d'
.cat -n
não é POSIX.grep -n '^'
numeraria todas as linhas (não é um problema para a saída ps que não possui linhas vazias).nl -ba -d $'\n'
numera cada linha.1b;...
não é portátil nem POSIX, não pode haver nenhum outro comando após "b"; portanto, você precisa de uma nova linha ou outra expressão -e.Como você se sente ao usar em
awk
vez degrep
?NR == 1
: Número de registro == 1; ie a primeira linha||
: ou:/syslogd/
: Padrão para procurarTambém pode valer a pena olhar
pgrep
, embora isso seja mais para scripts, em vez de saída voltada para o usuário.grep
Porém, evita que o próprio comando apareça na saída.fonte
EDIT: após comentários
Embora eu
head -1
lesse toda a entrada, mas depois de testá-la, também funciona.saída é
fonte
{ IFS='' read line; ... }
no caso de o cabeçalho começar com espaços.head -1
vez da combinação de leitura / eco.head -n1
no meu bash. Provavelmente, isso pode ser específico da implementação. Minha cabeça não está lendo toda a entrada neste caso, apenas a primeira linha, deixando o restante delas no buffer de entrada.head -n1
é mais curto, mas parece que até a especificação POSIX é silenciosa quanto a sua entrada é permitida a leitura, portanto, talvezread line; echo $line
seja mais portátil, afinal.Ps suporte filtro interno,
Suponha que você esteja procurando pelo processo bash:
ps -C bash -f
Irá listar todos os processos que nomearam
bash
.fonte
Costumo enviar o cabeçalho para stderr :
Isso geralmente é suficiente para fins de leitura humana. por exemplo:
A parte entre colchetes pode entrar em seu próprio script para uso geral.
Há uma conveniência adicional, pois a saída pode ser canalizada ainda mais (para
sort
etc.) e o cabeçalho permanecerá no topo.fonte
Você também pode usar
tee
ehead
:Observe, no entanto, que, desde que
tee
não seja possível ignorarSIGPIPE
sinais (consulte, por exemplo, a discussão aqui ), essa abordagem precisa de uma solução alternativa para ser confiável. A solução alternativa é ignorar os sinais SIGPIPE; isso pode, por exemplo, ser feito assim no bash como shells:Observe também que a ordem de saída não é garantida .
fonte
grep
:| { sleep .5; cat }
.Talvez dois
ps
comandos sejam mais fáceis.fonte
ps aux
chamada ... E se você quer apenas a primeira linha estática, por que não repetir manualmente?Você pode usar o pidstat com:
Exemplo:
Informações adicionais: http://linux.die.net/man/1/pidstat
fonte
Coloque o seguinte no seu arquivo .bashrc ou copie / cole no shell primeiro, para teste.
Uso: psls [padrão grep]
Certifique-se de fornecer seu arquivo .bashrc (ou .bash_profile, se você o colocar lá):
A função será concluída automaticamente na linha de comando do shell. Como você afirmou em outra resposta, você pode canalizar a primeira linha para um arquivo para salvar uma chamada em ps.
fonte
psl
, que apenas chamaps
egrep
uma vez cada (e não precisahead
).classifique, mas mantenha a linha do cabeçalho no topo
E use assim
fonte
Graças principalmente a Janis Papanagnou no comp.unix.shell, eu uso a seguinte função:
Isso tem várias vantagens:
-i
para correspondência sem distinção entre maiúsculas e minúsculas,-E
para expressões regulares ampliadas etc.Exemplo de uso:
fonte
Outra maneira com
gnu ed
:ou, se o shell suportar a substituição do processo:
isso é:
Mais portátil, sem
gnu
'!'
substituição de shell ou - usando apenas oed
built-inr
parar
direcionar a saídaps aux
para o buffer e, em seguida, excluir linhas não correspondentes no2,$
intervalo e imprimir o resultado:E como os
sed
comandos na resposta aceita também geram a linha correspondente, com umsed
que suporta-f-
e um shell que suporta a substituição de processos, eu executaria:que praticamente faz a mesma coisa que os
ed
comandos anteriores .fonte
O caminho Perl:
Muito mais fácil de ler do que
sed
, mais rápido, sem risco de escolher linhas indesejadas.fonte
Se isso for apenas para processos grepping com cabeçalhos completos, eu expandiria a sugestão do @ mrb:
pgrep bash | xargs ps -fp
obterá o mesmo resultado, mas sem um subshell. Se for necessária outra formatação:fonte
Se você conhece os números exatos das linhas, é fácil com o perl! Se você deseja obter as linhas 1 e 5 de um arquivo, diga / etc / passwd:
Se você quiser obter outras linhas também, basta adicionar seus números na matriz.
fonte