¿Cómo especificar más espacios para el delimitador usando cut?

195

¿Hay alguna forma de especificar un delimitador de campo para más espacios con el comando de corte? (como "" +)? Por ejemplo: en la siguiente cadena, me gusta alcanzar el valor '3744', ¿qué delimitador de campo debo decir?

$ps axu | grep jboss

jboss     2574  0.0  0.0   3744  1092 ?        S    Aug17   0:00 /bin/sh /usr/java/jboss/bin/run.sh -c example.com -b 0.0.0.0

cut -d' ' no es lo que quiero, ya que es solo para un solo espacio. awkno es lo que estoy buscando tampoco, pero ¿cómo hacer con 'cortar'?

Gracias.

leslie
fuente
13
La mejor respuesta es usar trcomo se muestra aquí: stackoverflow.com/a/4483833/168143
John Bachir
1
No es directamente relevante para la pregunta real que se hace, pero en lugar de ps+ grep, puede usar el pgrepque está disponible en la mayoría de las distribuciones modernas. Le devolverá el resultado exactamente en la forma en que lo necesita.
ccpizza

Respuestas:

322

En realidad awkes exactamente la herramienta que deberías estar buscando:

ps axu | grep '[j]boss' | awk '{print $5}'

o puedes deshacerte del greptodo ya que awkconoce las expresiones regulares:

ps axu | awk '/[j]boss/ {print $5}'

Pero si, por alguna extraña razón, realmente no puedes usarawk , hay otras cosas más simples que puede hacer, como contraer primero todos los espacios en blanco en un solo espacio:

ps axu | grep '[j]boss' | sed 's/\s\s*/ /g' | cut -d' ' -f5

Ese grep truco, por cierto, es una forma ordenada de obtener solo los jbossprocesos y no el grep jbossuno (lo mismo para elawk variante).

El grepproceso tendrá un literalgrep [j]boss en su comando de proceso, por lo que no será capturado por el grepmismo, que busca la clase de caracteres [j]seguida deboss .

Esta es una manera ingeniosa de evitar el | grep xyz | grep -v grepparadigma que usan algunas personas.

paxdiablo
fuente
1
Gran respuesta. Volveré a buscar esto de nuevo la próxima vez que lo necesite.
funroll
El greptruco parece no funcionar en los archivos crontab. ¿Cualquier razón?
Amir Ali Akbari
2
Sigo aprendiendo y olvidando el truco grep. Gracias por mi recordatorio más reciente. Quizás esta vez se pegue. Pero no apostaría por eso.
Michael Burr
@Michael, deberías configurar un trabajo cron en algún lugar para enviarte esa propina (y posiblemente otras) una vez al mes :-)
paxdiablo
3
Oliver, a veces la mejor respuesta a "¿cómo hago X con Y?" es "No uses Y, usa Z en su lugar". Dado que OP aceptó esta respuesta, es probable que los convenciera de eso :-)
paxdiablo
113

awkLa versión es probablemente la mejor opción, pero también puedes usarla cutsi primero aprietas las repeticiones con tr:

ps axu | grep jbos[s] | tr -s ' ' | cut -d' ' -f5
#        ^^^^^^^^^^^^   ^^^^^^^^^   ^^^^^^^^^^^^^
#              |            |             |
#              |            |       get 5th field
#              |            |
#              |        squeeze spaces
#              |
#        avoid grep itself to appear in the list
fedorqui 'así que deja de dañar'
fuente
10
Ilustración de lujo
Haggra
tr -s ' 'es muy lindo! Espero poder recordar eso mejor queawk
Chris
@ Chris tengo que objetar: ¡D Awk es mucho mejor para estas cosas!
fedorqui 'SO deja de dañar'
41

Me gusta usar el comando tr -s para esto

 ps aux | tr -s [:blank:] | cut -d' ' -f3

Esto exprime todos los espacios en blanco a 1 espacio. De esta manera, decir corte para usar un espacio como delimitador se cumple como se esperaba.

RobertDeRose
fuente
1
Creo que esta debería ser la respuesta, está más cerca de la solicitud de OP (se le pide que use cortar). Este enfoque es 5-10% más lento que el enfoque awk (porque hay una tubería más para manejar con tr), pero en general esto será irrelevante.
Oliver
11

Voy a nominar tr -s [:blank:]como la mejor respuesta.

¿Por qué queremos usar cortar? Tiene el comando mágico que dice "queremos el tercer campo y cada campo después de él, omitiendo los dos primeros campos"

cat log | tr -s [:blank:] |cut -d' ' -f 3- 

No creo que haya un comando equivalente para la división awk o perl donde no sabemos cuántos campos habrá, es decir, colocar el tercer campo en el campo X.

Wayne Mehl
fuente
9

Solución más corta / simple: uso cuts(corte en esteroides que escribí)

ps axu | grep '[j]boss' | cuts 4

Tenga en cuenta que cutslos índices de campo están basados ​​en cero, por lo que el quinto campo se especifica como 4

http://arielf.github.io/cuts/

E incluso más corto (sin usar corte en absoluto) es:

pgrep jboss
arielf
fuente
8

Una forma de evitar esto es ir:

$ps axu | grep jboss | sed 's/\s\+/ /g' | cut -d' ' -f3

para reemplazar múltiples espacios consecutivos con uno solo.

Jared Ng
fuente
Extraño, esto no funciona en OS X. El comando sed no cambia múltiples espacios a un espacio.
rjurney
2
\ses una extensión de sed de GNU. En OS X, puede pasar la -Ebandera a sed para habilitar expresiones regulares extendidas, luego usar [[:space:]]en lugar de \s, así:sed -E 's/[[:space:]]+/ /g'
Jared Ng
4

Personalmente, tiendo a usar awk para trabajos como este. Por ejemplo:

ps axu| grep jboss | grep -v grep | awk '{print $5}'
paulsm4
fuente
66
Eso se puede comprimir a ps axu | awk '/[j]boss/ {print $5}'.
zwol
1
¿No es más lento (especialmente cuando hay otros procesos superfluos), entonces sed / grep / cut?
pihentagy
2

Como alternativa, siempre hay perl:

ps aux | perl -lane 'print $F[3]'

O, si desea obtener todos los campos comenzando en el campo # 3 (como se indica en una de las respuestas anteriores):

ps aux | perl -lane 'print @F[3 .. scalar @F]'
flitz
fuente
Esto no funciona con la salida de lsofIntenté lsof|perl -lane 'print $F[5]'esto a veces obtiene la quinta columna, a veces la sexta
rubo77
Creo que la pregunta era cómo usar delimitadores que pudieran contener un número variable de espacios. Para este propósito la respuesta fue correcta.
Flitz 01 de
En lsof el problema es que el número de columnas no siempre es consistente en cada fila.
Flitz 01 de
2

Si desea elegir columnas de una salida ps, ¿alguna razón para no usar -o?

p.ej

ps ax -o pid,vsz
ps ax -o pid,cmd

Ancho de columna mínimo asignado, sin relleno, solo separador de campo de espacio único.

ps ax --no-headers -o pid:1,vsz:1,cmd

3443 24600 -bash
8419 0 [xfsalloc]
8420 0 [xfs_mru_cache]
8602 489316 /usr/sbin/apache2 -k start
12821 497240 /usr/sbin/apache2 -k start
12824 497132 /usr/sbin/apache2 -k start

Pid y vsz tienen un ancho de 10 caracteres, un separador de campo de 1 espacio.

ps ax --no-headers -o pid:10,vsz:10,cmd

  3443      24600 -bash
  8419          0 [xfsalloc]
  8420          0 [xfs_mru_cache]
  8602     489316 /usr/sbin/apache2 -k start
 12821     497240 /usr/sbin/apache2 -k start
 12824     497132 /usr/sbin/apache2 -k start

Utilizado en un script: -

oldpid=12824
echo "PID: ${oldpid}"
echo "Command: $(ps -ho cmd ${oldpid})"
Miguel
fuente
0

Otra forma si debe usar el comando de corte

ps axu | grep [j]boss |awk '$1=$1'|cut -d' ' -f5

En Solaris, reemplace awk con nawko/usr/xpg4/bin/awk

BMW
fuente
0

Todavía me gusta la forma en que Perl maneja los campos con espacios en blanco.
El primer campo es $ F [0].

$ ps axu | grep dbus | perl -lane 'print $F[4]'
AAAfarmclub
fuente
0

Mi enfoque es almacenar el PID en un archivo en / tmp, y encontrar el proceso correcto usando la -Sopción parassh . Eso podría ser un mal uso, pero funciona para mí.

#!/bin/bash

TARGET_REDIS=${1:-redis.someserver.com}
PROXY="proxy.somewhere.com"

LOCAL_PORT=${2:-6379}

if [ "$1" == "stop" ] ; then
    kill `cat /tmp/sshTunel${LOCAL_PORT}-pid`
    exit
fi

set -x

ssh -f -i ~/.ssh/aws.pem centos@$PROXY -L $LOCAL_PORT:$TARGET_REDIS:6379 -N -S /tmp/sshTunel$LOCAL_PORT  ## AWS DocService dev, DNS alias
# SSH_PID=$! ## Only works with &
SSH_PID=`ps aux | grep sshTunel${LOCAL_PORT} | grep -v grep | awk '{print $2}'`
echo $SSH_PID > /tmp/sshTunel${LOCAL_PORT}-pid

Un mejor enfoque podría ser consultar el SSH_PIDderecho antes de matarlo, ya que el archivo podría estar obsoleto y mataría un proceso incorrecto.

Ondra Žižka
fuente