Jak określić więcej spacji dla separatora za pomocą cut?

196

Czy istnieje sposób określenia ogranicznika pola dla większej liczby spacji za pomocą polecenia wycinania? (jak „” +)? Na przykład: w poniższym ciągu chciałbym osiągnąć wartość „3744”, jaki ogranicznik pola powinienem powiedzieć?

$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' 'nie jest tym, czego chcę, ponieważ dotyczy tylko jednego miejsca. awknie jest tym, czego szukam, ale jak zrobić z „cięciem”?

dzięki.

leslie
źródło
13
najlepszą odpowiedzią jest użycie trpokazanej tutaj: stackoverflow.com/a/4483833/168143
John Bachir
1
Nie dotyczy bezpośrednio zadawanego pytania, ale zamiast ps+ grepmożna użyć, pgrepktóry jest dostępny w większości nowoczesnych dystrybucji. Zwróci wynik dokładnie w takiej postaci, jakiej potrzebujesz.
ccpizza

Odpowiedzi:

323

W rzeczywistości awkjest to dokładnie narzędzie, na które powinieneś zwrócić uwagę:

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

lub możesz grepcałkowicie rzucić, ponieważ awkwie o wyrażeniach regularnych:

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

Ale jeśli z jakiegoś dziwnego powodu naprawdę nie możesz użyć awk, możesz wykonać inne prostsze rzeczy, takie jak zwinięcie wszystkich białych znaków w jednym miejscu:

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

grepNawiasem mówiąc, ta sztuczka jest dobrym sposobem na uzyskanie tylko jbossprocesów, a nie grep jbossjednego (to samo dotyczy awkwariantu).

grepProces będzie mieć dosłowne grep [j]bossw swojej komendzie procesowego tak nie zostanie złapany przez grepsiebie, która szuka klasa znaków [j]następuje boss.

To sprytny sposób na uniknięcie | grep xyz | grep -v grepparadygmatu, z którego korzystają niektórzy ludzie.

paxdiablo
źródło
1
Świetna odpowiedź. Wrócę, aby sprawdzić to następnym razem, gdy będę tego potrzebować.
funroll
grepSztuczka wydaje się nie działać w plikach crontab. Jakiegokolwiek powodu?
Amir Ali Akbari,
2
Uczę się i zapominam o grep tricku. Dziękuję za moje ostatnie przypomnienie. Może tym razem będzie się trzymać. Ale nie postawiłbym na to.
Michael Burr
@Michael, powinieneś gdzieś ustawić cron, aby raz w miesiącu przesyłać ci tę wskazówkę (i ewentualnie inne) :-)
paxdiablo
3
Oliver, czasem najlepsza odpowiedź na „jak zrobić X z Y?” to „Nie używaj Y, zamiast tego użyj Z”. Ponieważ OP zaakceptował tę odpowiedź, prawdopodobnie przekonałem ich o tym :-)
paxdiablo
113

awkwersja jest prawdopodobnie najlepszym sposobem, aby przejść, ale możesz również użyć, cutjeśli najpierw ściśniesz powtórzenia za pomocą 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 przestań szkodzić”
źródło
10
Fantazyjna ilustracja.
Haggra,
tr -s ' 'jest naprawdę niezły! Mam nadzieję, że pamiętam to lepiej niżawk
Chris,
@Chris Muszę się sprzeciwić: D Awk jest o wiele lepszy dla tych rzeczy !!
fedorqui „SO przestań szkodzić”
41

W tym celu lubię używać polecenia tr -s

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

To ściska wszystkie białe spacje do 1 pola. W ten sposób polecenie cut, aby używało spacji jako separatora, jest honorowane zgodnie z oczekiwaniami.

RobertDeRose
źródło
1
Myślę, że powinna to być odpowiedź, jest bliższa prośbie OP (poproszona o użycie cut). To podejście jest 5-10% wolniejsze niż podejście awk (ponieważ jest jeszcze jedna rura do obsługi z tr), ale ogólnie nie będzie to miało znaczenia.
Oliver,
11

Mam zamiar nominować tr -s [:blank:]jako najlepszą odpowiedź.

Dlaczego chcemy używać cięcia? Ma magiczne polecenie, które mówi: „chcemy trzeciego pola i każdego pola po nim, pomijając pierwsze dwa pola”

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

Nie sądzę, aby istniało równoważne polecenie podziału awk lub perl, w którym nie wiemy, ile będzie pól, tzn. Nie wprowadzaj trzeciego pola przez pole X.

Wayne Mehl
źródło
9

Krótsze / prostsze rozwiązanie: użyj cuts(nacięcie na sterydy, które napisałem)

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

Zauważ, że cutsindeksy pól są zerowe, więc piąte pole jest określone jako 4

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

A jeszcze krótszy (w ogóle nie używając cięcia) to:

pgrep jboss
arielf
źródło
8

Można to obejść:

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

aby zastąpić wiele kolejnych spacji jednym.

Jared Ng
źródło
Dziwne, to nie działa w systemie OS X. Polecenie sed nie zmienia wielu spacji w jedną spację.
rjurney
2
\sjest rozszerzeniem GNU sed. W systemie OS X można przekazać -Eflagę sed, aby włączyć rozszerzone wyrażenia regularne, a następnie użyć [[:space:]]zamiast \s:sed -E 's/[[:space:]]+/ /g'
Jared Ng
4

Osobiście używam awk do takich zadań. Na przykład:

ps axu| grep jboss | grep -v grep | awk '{print $5}'
paulsm4
źródło
6
Można to skompresować do ps axu | awk '/[j]boss/ {print $5}'.
zwolnić
1
Czy awk nie jest wolniejszy (szczególnie, gdy istnieją pewne zbędne inne procesy), a następnie sed / grep / cut?
pihentagy
2

Alternatywnie, zawsze istnieje perl:

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

Lub jeśli chcesz uzyskać wszystkie pola zaczynające się od pola nr 3 (jak podano w jednej z odpowiedzi powyżej):

ps aux | perl -lane 'print @F[3 .. scalar @F]'
flitz
źródło
To nie działa z danymi wyjściowymi, lsofktóre próbowałem, lsof|perl -lane 'print $F[5]'czasami dostaje 5 kolumnę, czasem 6
rubo77
Myślę, że pytaniem było po prostu, jak używać ograniczników, które mogą zawierać różną liczbę spacji. W tym celu odpowiedź była prawidłowa.
flitz
Problem polega na tym, że liczba kolumn nie zawsze jest spójna w każdym wierszu.
flitz
2

Jeśli chcesz wybrać kolumny z danych wyjściowych ps, masz powód, aby nie używać opcji -o?

na przykład

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

Przydzielona minimalna szerokość kolumny, bez wypełnienia, tylko separator pojedynczego pola spacji.

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 i vsz otrzymali 10 znaków szerokości, 1 separator pól spacji.

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

Używane w skrypcie: -

oldpid=12824
echo "PID: ${oldpid}"
echo "Command: $(ps -ho cmd ${oldpid})"
Mikrofon
źródło
0

Innym sposobem, jeśli musisz użyć polecenia cut

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

W systemie Solaris zamień awk na nawklub/usr/xpg4/bin/awk

BMW
źródło
0

Nadal podoba mi się sposób, w jaki Perl obsługuje pola z białą przestrzenią.
Pierwsze pole to $ F [0].

$ ps axu | grep dbus | perl -lane 'print $F[4]'
AAAfarmclub
źródło
0

Moje podejście polega na zapisaniu PID w pliku w / tmp i znalezieniu właściwego procesu przy użyciu -Sopcji dla ssh. To może być niewłaściwe użycie, ale działa dla mnie.

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

Lepszym rozwiązaniem może być zapytanie o SSH_PIDprawo przed jego zabiciem, ponieważ plik może być nieaktualny i zabiłoby to niewłaściwy proces.

Ondra Žižka
źródło