Comment spécifier plus d'espaces pour le délimiteur en utilisant couper?

196

Existe-t-il un moyen de spécifier un délimiteur de champ pour plus d'espaces avec la commande cut? (comme "" +)? Par exemple: dans la chaîne suivante, j'aime atteindre la valeur '3744', quel délimiteur de champ dois-je dire?

$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' 'ce n'est pas ce que je veux, car ce n'est que pour un seul espace. awkn'est pas ce que je recherche non plus, mais comment faire avec 'cut'?

Merci.

leslie
la source
13
meilleure réponse utilise trcomme indiqué ici: stackoverflow.com/a/4483833/168143
John Bachir
1
Pas directement lié à la question posée, mais au lieu de ps+, grepvous pouvez utiliser pgrepce qui est disponible dans la plupart des distributions modernes. Il renverra le résultat exactement sous la forme dont vous avez besoin.
ccpizza

Réponses:

323

En fait, awkc'est exactement l'outil que vous devriez étudier:

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

ou vous pouvez abandonner le greptout car il awkconnaît les expressions régulières:

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

Mais si, pour une raison étrange, vous ne pouvez vraiment pas l' utiliser awk, vous pouvez faire d'autres choses plus simples, comme réduire d'abord tous les espaces en un seul espace:

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

Cette grepastuce, soit dit en passant, est un bon moyen d'obtenir uniquement les jbossprocessus et non grep jbosscelui (idem pour la awkvariante également).

Le grepprocessus aura un littéral grep [j]bossdans sa commande process, il ne sera donc pas pris par greplui - même, qui recherche la classe de caractères [j]suivie par boss.

C'est une façon astucieuse d'éviter le | grep xyz | grep -v grepparadigme que certaines personnes utilisent.

paxdiablo
la source
1
Très bonne réponse. Je reviendrai le chercher la prochaine fois que j'en aurai besoin.
funroll
L' grepastuce ne semble pas fonctionner dans les fichiers crontab. N'importe quelle raison?
Amir Ali Akbari
2
Je continue d'apprendre et d'oublier l'astuce grep. Merci pour mon dernier rappel. Peut-être que cette fois ça va coller. Mais je ne parierais pas dessus.
Michael Burr du
@Michael, vous devriez mettre en place un travail cron quelque part pour vous envoyer cette astuce (et peut-être d'autres) une fois par mois :-)
paxdiablo
3
Oliver, parfois la meilleure réponse à "comment faire X avec Y?" est "N'utilisez pas Y, utilisez plutôt Z". Depuis qu'OP a accepté cette réponse, il est probable que je les ai convaincus de cela :-)
paxdiablo
113

awkla version est probablement la meilleure façon de procéder, mais vous pouvez également l'utiliser cutsi vous appuyez d'abord sur les répétitions avec 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 'SO arrête de nuire'
la source
10
Illustration de fantaisie.
Haggra
tr -s ' 'est très bien! J'espère que je m'en souviendrai mieux queawk
Chris
@Chris Je dois objecter: D Awk est bien meilleur pour ces choses !!
fedorqui 'SO arrête de nuire'
41

J'aime utiliser la commande tr -s pour cela

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

Cela réduit tous les espaces blancs à 1 espace. De cette façon, dire à cut d'utiliser un espace comme délimiteur est honoré comme prévu.

RobertDeRose
la source
1
Je pense que cela devrait être la réponse, c'est plus proche de la demande OP (demandé d'utiliser cut). Cette approche est 5 à 10% plus lente que l'approche awk (car il y a un tuyau de plus à gérer avec tr), mais en général, cela ne sera pas pertinent.
Oliver
11

Je vais proposer tr -s [:blank:]comme meilleure réponse.

Pourquoi voulons-nous utiliser la coupe? Il a la commande magique qui dit "nous voulons le troisième champ et chaque champ après, en omettant les deux premiers champs"

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

Je ne crois pas qu'il existe une commande équivalente pour le fractionnement awk ou perl où nous ne savons pas combien de champs il y aura, c'est-à-dire que le troisième champ sera mis à travers le champ X.

Wayne Mehl
la source
9

Solution plus courte / plus simple: utiliser cuts(couper sur les stéroïdes que j'ai écrits)

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

Notez que cutsles index de champ sont basés sur zéro, donc le 5ème champ est spécifié comme 4

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

Et encore plus court (ne pas utiliser de coupe du tout) est:

pgrep jboss
arielf
la source
8

Un moyen de contourner cela est d’aller:

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

pour remplacer plusieurs espaces consécutifs par un seul.

Jared Ng
la source
Étrange, cela ne fonctionne pas sur OS X. La commande sed ne change pas plusieurs espaces en un seul espace.
rjurney
2
\sest une extension GNU sed. Sur OS X, vous pouvez passer le -Edrapeau à sed pour activer les expressions régulières étendues, puis utiliser [[:space:]]à la place de \s, comme ceci:sed -E 's/[[:space:]]+/ /g'
Jared Ng
4

Personnellement, j'ai tendance à utiliser awk pour des emplois comme celui-ci. Par exemple:

ps axu| grep jboss | grep -v grep | awk '{print $5}'
paulsm4
la source
6
Cela peut être réduit à ps axu | awk '/[j]boss/ {print $5}'.
zwol
1
N'est-ce pas awk plus lent (surtout quand il y a d'autres processus superflus), puis sed / grep / cut?
pihentagy
2

Comme alternative, il y a toujours perl:

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

Ou, si vous souhaitez obtenir tous les champs à partir du champ n ° 3 (comme indiqué dans l'une des réponses ci-dessus):

ps aux | perl -lane 'print @F[3 .. scalar @F]'
flitz
la source
Cela ne fonctionne pas avec la sortie de lsofJ'ai essayé lsof|perl -lane 'print $F[5]'cela obtient parfois la 5ème colonne, parfois la 6ème
rubo77
Je pense que la question était simplement de savoir comment utiliser les délimiteurs qui pourraient contenir un nombre variable d'espaces. À cet effet, la réponse était correcte.
flitz
Dans lsof, le problème est que le nombre de colonnes n'est pas toujours cohérent dans chaque ligne.
flitz
2

Si vous souhaitez choisir des colonnes à partir d'une sortie ps, quelle raison de ne pas utiliser -o?

par exemple

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

Largeur de colonne minimale allouée, pas de remplissage, uniquement un séparateur de champ à espace unique.

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 et vsz étant donné une largeur de 10 caractères, 1 séparateur de champ d'espace.

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

Utilisé dans un script: -

oldpid=12824
echo "PID: ${oldpid}"
echo "Command: $(ps -ho cmd ${oldpid})"
Mike
la source
0

Une autre façon si vous devez utiliser la commande cut

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

Dans Solaris, remplacez awk par nawkou/usr/xpg4/bin/awk

BMW
la source
0

J'aime toujours la façon dont Perl gère les champs avec des espaces blancs.
Le premier champ est $ F [0].

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

Mon approche consiste à stocker le PID dans un fichier dans / tmp et à trouver le bon processus en utilisant l' -Soption pour ssh. Cela pourrait être une mauvaise utilisation, mais cela fonctionne pour moi.

#!/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

Une meilleure approche pourrait être de rechercher le SSH_PIDdroit avant de le tuer, car le fichier peut être périmé et tuer un mauvais processus.

Ondra Žižka
la source