Làm thế nào để xác định nhiều không gian hơn cho dấu phân cách bằng cách sử dụng cắt?


195

Có cách nào để chỉ định một dấu phân cách trường cho nhiều khoảng trắng hơn với lệnh cắt không? (như "" +)? Ví dụ: Trong chuỗi sau, tôi muốn đạt giá trị '3744', tôi nên nói dấu phân cách trường nào?

$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' 'không phải là điều tôi muốn, vì nó chỉ dành cho một không gian duy nhất. awkkhông phải là những gì tôi đang tìm kiếm, nhưng làm thế nào với 'cắt'?

cảm ơn.


13
câu trả lời hay nhất đang được sử dụng trnhư được hiển thị ở đây: stackoverflow.com/a/4483833/168143
John Bachir

1
Không liên quan trực tiếp đến câu hỏi thực tế đang được hỏi nhưng thay vì ps+ grepbạn có thể sử dụng câu hỏi pgrepcó sẵn trong hầu hết các bản phát hành hiện đại. Nó sẽ trả về kết quả chính xác theo hình thức bạn cần.
ccpizza

Câu trả lời:


322

Trên thực tế awkchính xác công cụ bạn nên nhìn vào:

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

hoặc bạn có thể bỏ grephoàn toàn kể từ khi awkbiết về các biểu thức thông thường:

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

Nhưng nếu, vì một lý do kỳ quái nào đó, bạn thực sự không thể sử dụng awk, có những thứ đơn giản khác bạn có thể làm, như thu gọn tất cả khoảng trắng vào một không gian trước tiên:

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

Tuy nhiên grep, mánh khóe đó là một cách gọn gàng để chỉ lấy các jbossquy trình chứ không phải grep jbossmột quy trình (ditto cho awkbiến thể là tốt).

Các grepquá trình sẽ có một chữ grep [j]bosstrong lệnh quá trình của nó như vậy sẽ không được đánh bắt bởi grepchính nó, mà là tìm kiếm các lớp nhân vật [j]tiếp theo boss.

Đây là một cách tiện lợi để tránh | grep xyz | grep -v grepmô hình mà một số người sử dụng.


1
Câu trả lời chính xác. Tôi sẽ trở lại để tìm kiếm lại lần sau khi tôi cần nó.
funroll

Thủ grepthuật dường như không hoạt động trong các tập tin crontab. Có lý do gì không?
Amir Ali Akbari

2
Tôi tiếp tục học và quên đi mánh khóe grep. Cảm ơn lời nhắc gần đây nhất của tôi. Có lẽ lần này nó sẽ dính. Nhưng tôi sẽ không đặt cược vào nó.
Michael Burr

@Michael, bạn nên thiết lập một công việc định kỳ ở đâu đó để gửi mẹo đó (và có thể là những người khác) cho bạn mỗi tháng một lần :-)
paxdiablo

3
Oliver, đôi khi câu trả lời tốt nhất cho "làm thế nào để tôi làm X với Y?" là "Đừng sử dụng Y, thay vào đó hãy sử dụng Z". Vì OP đã chấp nhận câu trả lời này, có khả năng tôi đã thuyết phục họ về điều đó :-)
paxdiablo

113

awkphiên bản có lẽ là cách tốt nhất để sử dụng, nhưng bạn cũng có thể sử dụng cutnếu trước tiên bạn lặp lại các lần lặp lại với tr:

ps axu | grep jbos[s] | tr -s ' ' | cut -d' ' -f5
#        ^^^^^^^^^^^^   ^^^^^^^^^   ^^^^^^^^^^^^^
#              |            |             |
#              |            |       get 5th field
#              |            |
#              |        squeeze spaces
#              |
#        avoid grep itself to appear in the list

9
Hình minh họa lạ mắt.
Haggra

tr -s ' 'là hùng mạnh tốt đẹp! Tôi hy vọng tôi có thể nhớ điều đó tốt hơnawk
Chris

@Chris Tôi phải phản đối: D Awk là cách tốt hơn cho những thứ này !!
fedorqui 'SO ngừng làm hại'

41

Tôi thích sử dụng lệnh tr -s cho việc này

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

Điều này ép tất cả các khoảng trắng xuống còn 1 khoảng trắng. Cách nói này để cắt sử dụng một không gian như một dấu phân cách được tôn vinh như mong đợi.


1
Tôi nghĩ rằng đây sẽ là câu trả lời, nó gần với yêu cầu của OP hơn (được yêu cầu sử dụng cắt). Cách tiếp cận này chậm hơn 5-10% so với cách tiếp cận awk (vì có thêm một đường ống để xử lý với tr), nhưng nói chung điều này sẽ không liên quan.
Oliver

11

Tôi sẽ đề cử tr -s [:blank:]là câu trả lời tốt nhất.

Tại sao chúng ta muốn sử dụng cắt? Nó có lệnh ma thuật nói rằng "chúng tôi muốn trường thứ ba và mọi trường sau nó, bỏ qua hai trường đầu tiên"

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

Tôi không tin rằng có một lệnh tương đương cho awk hoặc perl split trong đó chúng ta không biết sẽ có bao nhiêu trường, tức là đưa trường thứ 3 qua trường X.


9

Giải pháp ngắn hơn / đơn giản hơn: sử dụng cuts(cắt trên steroid tôi đã viết)

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

Lưu ý rằng cutscác chỉ mục trường là không dựa trên nên trường thứ 5 được chỉ định là 4

http://arielf.github.io/cut/

Và thậm chí ngắn hơn (hoàn toàn không sử dụng cắt) là:

pgrep jboss

8

Một cách để giải quyết vấn đề này là:

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

để thay thế nhiều không gian liên tiếp bằng một không gian duy nhất.


Thật kỳ lạ, điều này không hoạt động trên OS X. Lệnh sed không thay đổi nhiều không gian thành một không gian.
rjurney

2
\slà một phần mở rộng GNU sed. Trên OS X, bạn có thể chuyển -Ecờ sang sed để bật các biểu thức chính quy mở rộng, sau đó sử dụng [[:space:]]thay cho \s, như vậy:sed -E 's/[[:space:]]+/ /g'
Jared Ng

4

Cá nhân, tôi có xu hướng sử dụng awk cho các công việc như thế này. Ví dụ:

ps axu| grep jboss | grep -v grep | awk '{print $5}'

6
Điều đó có thể được nén xuống ps axu | awk '/[j]boss/ {print $5}'.
zwol

1
Không phải là chậm hơn (đặc biệt là khi có một số quy trình khác không cần thiết), sau đó sed / grep / cut?
pieaveragy

2

Thay thế, luôn luôn có perl:

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

Hoặc, nếu bạn muốn nhận tất cả các trường bắt đầu từ trường số 3 (như đã nêu trong một trong các câu trả lời ở trên):

ps aux | perl -lane 'print @F[3 .. scalar @F]'

Điều này không hoạt động với đầu ra của lsoftôi đã thử lsof|perl -lane 'print $F[5]', đôi khi có cột thứ 5, đôi khi là thứ 6
rubo77

Tôi nghĩ câu hỏi chỉ là làm thế nào để sử dụng các dấu phân cách có thể chứa một số lượng không gian khác nhau. Đối với mục đích này, câu trả lời là chính xác.
flitz

Trong lsof vấn đề là số lượng cột không phải lúc nào cũng nhất quán trong mỗi hàng.
flitz


2

Nếu bạn muốn chọn các cột từ đầu ra ps, lý do nào để không sử dụng -o?

ví dụ

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

Chiều rộng cột tối thiểu được phân bổ, không có phần đệm, chỉ có dấu tách trường không gian duy nhất.

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 và vsz cho 10 chiều rộng char, 1 dấu cách trường không gian.

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

Được sử dụng trong một tập lệnh: -

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

0

Một cách khác nếu bạn phải sử dụng lệnh cắt

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

Trong Solaris, thay thế awk bằng nawkhoặc/usr/xpg4/bin/awk


0

Tôi vẫn thích cách Perl xử lý các trường có khoảng trắng.
Trường đầu tiên là $ F [0].

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

0

Cách tiếp cận của tôi là lưu trữ PID vào một tệp trong / tmp và tìm đúng quy trình bằng cách sử dụng -Stùy chọn cho ssh. Đó có thể là một lạm dụng nhưng làm việc cho tôi.

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

Cách tiếp cận tốt hơn có thể là truy vấn SSH_PIDquyền trước khi giết nó, vì tệp có thể cũ và nó sẽ giết một quy trình sai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.