Bagaimana cara menentukan lebih banyak ruang untuk pembatas menggunakan cut?

195

Apakah ada cara untuk menentukan pembatas bidang untuk lebih banyak spasi dengan perintah cut? (seperti "" +)? Misalnya: Dalam string berikut, saya ingin mencapai nilai '3744', pembatas bidang apa yang harus saya katakan?

$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' 'bukan yang saya inginkan, karena itu hanya untuk satu ruang tunggal. awkbukan apa yang saya cari, tapi bagaimana hubungannya dengan 'cut'?

Terima kasih.

leslie
sumber
13
jawaban terbaik adalah menggunakan trseperti yang ditunjukkan di sini: stackoverflow.com/a/4483833/168143
John Bachir
1
Tidak secara langsung relevan dengan pertanyaan aktual yang diajukan tetapi alih-alih ps+ grepAnda dapat menggunakan pgrepyang tersedia di sebagian besar distro modern. Ini akan mengembalikan hasilnya persis dalam bentuk yang Anda butuhkan.
ccpizza

Jawaban:

322

Sebenarnya awkadalah persis alat Anda harus melihat ke dalam:

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

atau Anda dapat membuang grepsemuanya karena awktahu tentang ekspresi reguler:

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

Tetapi jika, untuk alasan yang aneh, Anda benar - benar tidak dapat menggunakan awk, ada hal-hal sederhana lain yang dapat Anda lakukan, seperti jatuhkan semua spasi putih ke ruang tunggal terlebih dahulu:

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

Itu greptrik, dengan cara, adalah cara yang rapi untuk hanya mendapatkan jbossproses dan bukan grep jbosssatu (ditto untuk awkvarian juga).

The grepProses akan memiliki literal grep [j]bossdalam perintah proses sehingga tidak akan tertangkap oleh grepsendiri, yang mencari kelas karakter [j]diikuti oleh boss.

Ini adalah cara yang bagus untuk menghindari | grep xyz | grep -v grepparadigma yang digunakan beberapa orang.

paxdiablo
sumber
1
Jawaban yang bagus Saya akan datang kembali untuk mencari ini lagi lain kali saya membutuhkannya.
funroll
The greptrick tampaknya tidak bekerja di file crontab. Alasan apapun?
Amir Ali Akbari
2
Saya terus belajar dan melupakan trik grep. Terima kasih atas pengingat terakhir saya. Mungkin kali ini akan menempel. Tapi saya tidak akan bertaruh.
Michael Burr
@Michael, Anda harus mengatur pekerjaan cron di suatu tempat untuk mengirimkan tip itu (dan mungkin orang lain) kepada Anda sebulan sekali :-)
paxdiablo
3
Oliver, kadang-kadang jawaban terbaik untuk "bagaimana saya melakukan X dengan Y?" adalah "Jangan gunakan Y, gunakan Z sebagai gantinya". Karena OP menerima jawaban ini, kemungkinan saya meyakinkan mereka tentang hal itu :-)
paxdiablo
113

awkversi mungkin adalah cara terbaik untuk pergi, tetapi Anda juga dapat menggunakan cutjika Anda terlebih dahulu menekan pengulangan dengan 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 berhenti merugikan'
sumber
10
Ilustrasi mewah.
Haggra
tr -s ' 'bagus sekali! Saya harap saya bisa mengingatnya lebih baik daripadaawk
Chris
@ Chris aku harus keberatan: D Awk jauh lebih baik untuk hal-hal ini !!
fedorqui 'SO berhenti merugikan'
41

Saya suka menggunakan perintah tr -s untuk ini

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

Ini meremas semua ruang putih hingga 1 ruang. Dengan cara ini, cut cut untuk menggunakan spasi sebagai pembatas dihormati seperti yang diharapkan.

RobertDeRose
sumber
1
Saya pikir ini harus menjadi jawaban, lebih dekat dengan permintaan OP (diminta untuk menggunakan cut). Pendekatan ini lebih lambat 5-10% daripada pendekatan awk (karena ada satu lagi pipa yang harus ditangani dengan tr), tetapi secara umum ini tidak akan relevan.
Oliver
11

Saya akan mencalonkan diri tr -s [:blank:]sebagai jawaban terbaik.

Mengapa kita ingin menggunakan cut? Ini memiliki perintah ajaib yang mengatakan "kami ingin bidang ketiga dan setiap bidang setelahnya, menghilangkan dua bidang pertama"

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

Saya tidak percaya ada perintah setara untuk awk atau perl split di mana kita tidak tahu berapa banyak bidang yang akan ada, yaitu keluar menempatkan bidang ke-3 melalui bidang X.

Wayne Mehl
sumber
9

Solusi yang lebih singkat / sederhana: gunakan cuts(kurangi steroid yang saya tulis)

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

Perhatikan bahwa cutsindeks bidang berbasiskan nol sehingga bidang ke-5 ditetapkan sebagai 4

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

Dan bahkan lebih pendek (tidak menggunakan potongan sama sekali) adalah:

pgrep jboss
diri sendiri
sumber
8

Salah satu cara untuk mengatasinya adalah dengan:

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

untuk mengganti beberapa spasi berturut-turut dengan satu.

Jared Ng
sumber
Aneh, ini tidak berfungsi pada OS X. Perintah sed tidak mengubah beberapa ruang menjadi satu ruang.
rjurney
2
\sadalah ekstensi sed GNU. Pada OS X Anda dapat mengedarkan -Eflag ke sed untuk mengaktifkan ekspresi reguler yang diperluas, kemudian digunakan [[:space:]]sebagai pengganti \s, seperti:sed -E 's/[[:space:]]+/ /g'
Jared Ng
4

Secara pribadi, saya cenderung menggunakan awk untuk pekerjaan seperti ini. Sebagai contoh:

ps axu| grep jboss | grep -v grep | awk '{print $5}'
paulsm4
sumber
6
Itu bisa dikompresi ke bawah ps axu | awk '/[j]boss/ {print $5}'.
zwol
1
Bukankah awk lebih lambat (terutama ketika ada beberapa proses lain yang berlebihan), kemudian sed / grep / cut?
pihentagy
2

Sebagai alternatif, selalu ada perl:

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

Atau, jika Anda ingin mendapatkan semua bidang mulai dari bidang # 3 (sebagaimana dinyatakan dalam salah satu jawaban di atas):

ps aux | perl -lane 'print @F[3 .. scalar @F]'
flitz
sumber
Ini tidak bekerja dengan output dari lsofsaya mencoba lsof|perl -lane 'print $F[5]'ini kadang-kadang mendapat kolom ke-5, kadang-kadang ke-6
rubo77
Saya pikir pertanyaannya hanyalah bagaimana menggunakan pembatas yang mungkin berisi jumlah ruang yang bervariasi. Untuk tujuan ini jawabannya benar.
Flitz
Salah satu masalahnya adalah jumlah kolom tidak selalu konsisten di setiap baris.
Flitz
2

Jika Anda ingin memilih kolom dari output ps, ada alasan untuk tidak menggunakan -o?

misalnya

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

Lebar kolom minimum dialokasikan, tanpa bantalan, hanya pemisah bidang spasi tunggal.

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 dan vsz diberi lebar char 10, 1 pemisah bidang spasi.

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

Digunakan dalam skrip: -

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

Cara lain jika Anda harus menggunakan perintah cut

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

Di Solaris, ganti awk dengan nawkatau/usr/xpg4/bin/awk

BMW
sumber
0

Saya masih suka cara Perl menangani bidang dengan ruang putih.
Bidang pertama adalah $ F [0].

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

Pendekatan saya adalah menyimpan PID ke file di / tmp, dan untuk menemukan proses yang tepat menggunakan -Sopsi untuk ssh. Itu mungkin penyalahgunaan tetapi bekerja untuk saya.

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

Pendekatan yang lebih baik mungkin untuk meminta SSH_PIDhak sebelum membunuhnya, karena file mungkin basi dan akan membunuh proses yang salah.

Ondra Žižka
sumber