Asumiendo un grep simple como:
$ psa aux | grep someApp
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
Esto proporciona mucha información, pero como falta la primera línea del comando ps no hay contexto para la información. Preferiría que también se muestre la primera línea de ps:
$ 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
Por supuesto, podría agregar una expresión regular a grep específicamente para ps:
$ ps aux | grep -E "COMMAND|someApp"
Sin embargo, preferiría una solución más general ya que hay otros casos en los que me gustaría tener la primera línea también.
Parece que este sería un buen caso de uso para un descriptor de archivo "stdmeta" .
bash
command-line
dotancohen
fuente
fuente
ack
son tan útiles, y porperl
último se dispararonsed
,awk
, etc en popularidad: es importante que las partes en suma en un todo coherente.-C
argumentops
ay no necesitaría canalizarlo a grep. por ejemplo,ps u -C someApp
o inclusops u -C app1 -C app2 -C app3
ps aux | { head -1; grep foo; }
mencionada por @Nahuel Fouilleul a continuación (la suya es probablemente la única solución que podría recordar en el acto si fuera necesario)Respuestas:
Buen camino
Normalmente no puede hacer esto con grep pero puede usar otras herramientas. AWK ya se mencionó, pero también puede usarlo
sed
así:Cómo funciona:
La utilidad Sed funciona en cada línea individualmente, ejecutando comandos específicos en cada una de ellas. Puede tener múltiples comandos, especificando varias
-e
opciones. Podemos anteponer cada comando con un parámetro de rango que especifica si este comando debe aplicarse a una línea específica o no."1p" es un primer comando. Utiliza un
p
comando que normalmente imprime todas las líneas. Pero lo anteponemos con un valor numérico que especifica el rango al que debe aplicarse. Aquí, usamos lo1
que significa primera línea. Si desea imprimir más líneas, puede usarx,yp
dóndex
está la primera línea para imprimir,y
es la última línea para imprimir. Por ejemplo, para imprimir las primeras 3 líneas, usaría1,3p
El siguiente comando es el
d
que normalmente elimina todas las líneas del búfer. Antes de este comando ponemosyourpattern
entre dos/
caracteres. Esta es la otra forma (primero fue especificar en qué líneas como hicimos con elp
comando) de direccionar las líneas en las que el comando debería estar ejecutándose. Esto significa que el comando solo funcionará para las líneas que coincidenyourpattern
. Excepto, usamos el!
carácter antes deld
comando que invierte su lógica. Entonces ahora eliminará todas las líneas que no coinciden con el patrón especificado.Al final, sed imprimirá todas las líneas que quedan en el búfer. Pero eliminamos las líneas que no coinciden del búfer, por lo que solo se imprimirán las líneas coincidentes.
Para resumir: imprimimos la primera línea, luego eliminamos todas las líneas que no coinciden con nuestro patrón de la entrada. Resto de las líneas se imprimen (tan sólo las líneas que hacen coincidir con el patrón).
Problema de primera línea
Como se mencionó en los comentarios, hay un problema con este enfoque. Si el patrón especificado coincide también con la primera línea, se imprimirá dos veces (una por
p
comando y otra por una coincidencia). Podemos evitar esto de dos maneras:Agregar
1d
comando después1p
. Como ya mencioné, eld
comando elimina líneas del búfer y especificamos su rango con el número 1, lo que significa que solo eliminará la primera línea. Entonces el comando seríased -e '1p' -e '1d' -e '/youpattern/!d'
Usando el
1b
comando, en lugar de1p
. Es un truco.b
El comando nos permite saltar a otro comando especificado por una etiqueta (de esta manera se pueden omitir algunos comandos). Pero si esta etiqueta no se especifica (como en nuestro ejemplo) simplemente salta al final de los comandos, ignorando el resto de los comandos para nuestra línea. Entonces, en nuestro caso, el últimod
comando no eliminará esta línea del búfer.Ejemplo completo:
Usando punto y coma
Algunas
sed
implementaciones pueden ahorrarle algo de tipeo usando punto y coma para separar comandos en lugar de usar múltiples-e
opciones. Entonces, si no te importa ser portátil, el comando seríaps aux | sed '1b;/syslog/!d'
. Funciona al menos enGNU sed
ebusybox
implementaciones.Manera loca
Aquí hay, sin embargo, una forma bastante loca de hacer esto con grep. Definitivamente no es óptimo, estoy publicando esto solo con fines de aprendizaje, pero puede usarlo, por ejemplo, si no tiene ninguna otra herramienta en su sistema:
Cómo funciona
Primero, usamos la
-n
opción para agregar números de línea antes de cada línea. Queremos numerar todas las líneas que estamos haciendo coincidir.*
, cualquier cosa, incluso una línea vacía. Como se sugiere en los comentarios, también podemos hacer coincidir '^', el resultado es el mismo.Luego estamos usando expresiones regulares extendidas para que podamos usar
\|
caracteres especiales que funcionen como OR. Entonces, hacemos coincidir si la línea comienza con1:
(primera línea) o contiene nuestro patrón (en este caso, susyslog
).Problema de números de línea
Ahora el problema es que estamos obteniendo estos números de línea feos en nuestra salida. Si esto es un problema, podemos eliminarlos de
cut
esta manera:-d
La opción especifica delimitador,-f
especifica los campos (o columnas) que queremos imprimir. Por lo tanto, queremos cortar cada línea en cada:
carácter e imprimir solo la segunda y todas las columnas posteriores. Esto elimina efectivamente la primera columna con su delimitador y esto es exactamente lo que necesitamos.fuente
cat -n
y se vería más clara como con un grep abusado por esto.nl
no cuenta líneas vacías (pero las imprime sin número de línea),cat -n
formatea la numeración con espacios anteriores,grep -n .
elimina las líneas vacías y agrega dos puntos. Todos tienen sus ... er ... características ;-)ps aux | sed '1p;/pattern/!d'
imprimirá la primera línea dos veces si coincide con el patrón . Lo mejor es utilizado elb
comando:ps aux | sed -e 1b -e '/pattern/!d'
.cat -n
No es POSIX.grep -n '^'
numeraría cada línea (no es un problema para la salida ps que no tiene líneas vacías).nl -ba -d $'\n'
numera cada línea.1b;...
no es portátil ni POSIX, no puede haber ningún otro comando después de "b", por lo que necesita una nueva línea u otra expresión -e.¿Cómo te sientes acerca de usar en
awk
lugar degrep
?NR == 1
: Número de registro == 1; es decir. la primera linea||
: o:/syslogd/
: Patrón para buscarTambién podría valer la pena mirarlo
pgrep
, aunque esto es más para los scripts que para la salida orientada al usuario. Sin embargo, evita que elgrep
comando en sí aparezca en la salida.fuente
EDITAR: después de los comentarios
Pensé
head -1
que leería todas las entradas, pero después de probarlo, también funciona.la salida es
fuente
{ IFS='' read line; ... }
en caso de que el encabezado comience con espacios.head -1
lugar del combo de lectura / eco.head -n1
en mi fiesta. Esto probablemente puede ser específico de la implementación. Mi cabeza no está leyendo toda la entrada en este caso, solo la primera línea, dejando el resto en el búfer de entrada.head -n1
es más corto, pero parece que incluso la especificación POSIX no dice cuánto de su entrada puede leer, por lo que quizásread line; echo $line
sea más portátil después de todo.Ps admite filtro interno,
Supongamos que está buscando un proceso bash:
ps -C bash -f
Enumerará todos los procesos que nombraron
bash
.fuente
Tiendo a enviar el encabezado a stderr :
Esto suele ser suficiente para fines de lectura humana. p.ej:
La parte entre corchetes podría ir en su propio guión para uso general.
Hay una conveniencia adicional en que la salida se puede canalizar más (a
sort
etc.) y el encabezado permanecerá en la parte superior.fuente
También puedes usar
tee
yhead
:Sin embargo,
tee
tenga en cuenta que, mientras no pueda ignorar lasSIGPIPE
señales (ver, por ejemplo, la discusión aquí ), este enfoque necesita una solución alternativa para ser confiable. La solución alternativa es ignorar las señales SIGPIPE, esto se puede hacer, por ejemplo, en bash como shells:También tenga en cuenta que el orden de salida no está garantizado .
fuente
grep
:| { sleep .5; cat }
.Quizás dos
ps
comandos serían los más fáciles.fuente
ps aux
llamada ... Y si solo quieres esa primera línea estática, ¿por qué no repetirla manualmente?Podrías usar pidstat con:
Ejemplo:
Más información: http://linux.die.net/man/1/pidstat
fuente
Ponga lo siguiente en su archivo .bashrc o copie / pegue en el shell primero, para probar.
Uso: psls [patrón grep]
Asegúrese de obtener su .bashrc (o .bash_profile si lo coloca allí):
La función incluso se completará automáticamente en la línea de comandos del shell. Como indicó en otra respuesta, puede canalizar la primera línea a un archivo para guardar una llamada a ps.
fuente
psl
, que solo llamaps
ygrep
una vez cada una (y no necesitahead
).ordenar pero mantener la línea de encabezado en la parte superior
Y úsalo así
fuente
Gracias principalmente a Janis Papanagnou en comp.unix.shell, uso la siguiente función:
Esto tiene una serie de ventajas:
-i
para coincidencias que no distingan entre mayúsculas y minúsculas,-E
para expresiones regulares extendidas, etc.Ejemplo de uso:
fuente
Otra forma con
gnu ed
:o, si el shell admite la sustitución del proceso:
es decir:
Más portátil, sin
gnu
'!'
sustitución de shell, utilizando solo eled
incorporador
parar
enviar la salidaps aux
al búfer y luego eliminar las líneas que no coinciden en el2,$
rango e imprimir el resultado:Y dado que los
sed
comandos en la respuesta aceptada también muestran la línea que coinciden, con unased
que admite-f-
y una shell que admite la sustitución de procesos, ejecutaría:que prácticamente hace lo mismo que los
ed
comandos anteriores .fuente
El camino de Perl:
Mucho más fácil de leer que
sed
, más rápido, sin riesgo de elegir líneas no deseadas.fuente
Si eso es solo para procesos grepping con encabezados completos, expandiría la sugerencia de @ mrb:
pgrep bash | xargs ps -fp
obtendrá el mismo resultado pero sin una subshell. Si se requiere otro formato:fuente
Si conoce los números de línea exactos, ¡es fácil con perl! Si desea obtener las líneas 1 y 5 de un archivo, diga / etc / passwd:
Si desea obtener otras líneas también, simplemente agregue sus números en la matriz.
fuente