จะระบุช่องว่างเพิ่มเติมสำหรับตัวคั่นโดยใช้การตัดได้อย่างไร


196

มีวิธีใดที่จะระบุตัวคั่นฟิลด์สำหรับช่องว่างเพิ่มเติมด้วยคำสั่ง cut หรือไม่? (เช่น "" +)? ตัวอย่างเช่น: ในสตริงต่อไปนี้ฉันต้องการเข้าถึงค่า '3744' ตัวคั่นฟิลด์ใดที่ฉันควรพูด

$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' 'ไม่ใช่สิ่งที่ฉันต้องการเพราะมันมีเพียงพื้นที่เดียวเท่านั้น awkไม่ใช่สิ่งที่ฉันกำลังมองหา แต่จะทำอย่างไรกับ 'ตัด'?

ขอบคุณ


13
คำตอบที่ดีที่สุดใช้trตามที่แสดงไว้ที่นี่: stackoverflow.com/a/4483833/168143
John Bachir

1
ไม่เกี่ยวข้องโดยตรงกับคำถามจริงที่ถูกถาม แต่แทนที่จะเป็นps+ grepคุณสามารถใช้pgrepซึ่งมีอยู่ใน distros ที่ทันสมัยที่สุด มันจะส่งคืนผลลัพธ์ตรงตามที่คุณต้องการ
ccpizza

คำตอบ:


323

ที่จริงawkคือว่าเครื่องมือที่คุณควรจะมองเป็น:

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

หรือคุณสามารถทิ้งทุกgrepอย่างตั้งแต่awkรู้เกี่ยวกับนิพจน์ทั่วไป:

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

แต่ถ้าด้วยเหตุผลที่แปลกประหลาดคุณไม่สามารถใช้งานได้จริงawkมีสิ่งที่ง่ายกว่าที่คุณสามารถทำได้เช่นยุบพื้นที่ทั้งหมดไปยังพื้นที่เดียวก่อน:

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

ว่าgrepเคล็ดลับโดยวิธีการที่เป็นวิธีที่เรียบร้อยจะได้รับเพียงjbossกระบวนการและไม่ได้เป็นgrep jbossหนึ่ง (เหมือนกันสำหรับawkตัวแปรเช่นกัน)

grepกระบวนการจะมีตัวอักษรgrep [j]bossในคำสั่งของกระบวนการเช่นนี้จะไม่ถูกจับโดยgrepตัวเองซึ่งกำลังมองหาตัวอักษรชั้นเรียนตาม[j]boss

นี่เป็นวิธีที่ดีที่จะหลีกเลี่ยง| grep xyz | grep -v grepกระบวนทัศน์ที่บางคนใช้


1
คำตอบที่ดี ฉันจะกลับมาค้นหาอีกครั้งในครั้งต่อไปที่ฉันต้องการ
funroll

grepเคล็ดลับดูเหมือนว่าจะไม่ได้ทำงานในแฟ้ม crontab ด้วยเหตุผลใด
Amir Ali Akbari

2
ฉันเรียนรู้และลืมเคล็ดลับ grep ต่อไป ขอบคุณสำหรับการเตือนล่าสุดของฉัน บางทีคราวนี้มันจะติด แต่ฉันจะไม่เดิมพัน
Michael Burr

@Michael คุณควรตั้งค่างาน cron ที่ไหนสักแห่งเพื่อส่งเคล็ดลับ (และอาจเป็นไปได้อื่น ๆ ) ให้คุณเดือนละครั้ง :-)
paxdiablo

3
โอลิเวอร์บางครั้งคำตอบที่ดีที่สุดสำหรับ "ฉันจะทำ X กับ Y ได้อย่างไร" คือ "อย่าใช้ Y ใช้ Z แทน" ตั้งแต่ OP ได้รับการยอมรับคำตอบนี้ก็มีแนวโน้มที่ฉันทำให้พวกเขาเชื่อว่า :-)
paxdiablo

113

awkรุ่นอาจเป็นวิธีที่ดีที่สุด แต่คุณสามารถใช้cutถ้าคุณบีบย้ำซ้ำด้วยtr:

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

10
ภาพประกอบแฟนซี
Haggra

tr -s ' 'เป็นสิ่งที่ดีมาก! ฉันหวังว่าฉันจะจำได้ดีกว่าawk
Chris

@ Chris ฉันต้องคัดค้าน: D Awk ดีกว่าสำหรับสิ่งเหล่านี้ !!
fedorqui 'ดังนั้นหยุดทำอันตราย'

41

ฉันชอบใช้คำสั่ง tr -s สำหรับสิ่งนี้

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

สิ่งนี้บีบช่องว่างสีขาวทั้งหมดลงไปที่ 1 ช่องว่าง วิธีนี้บอกให้ตัดเพื่อใช้พื้นที่เป็นตัวคั่นได้รับเกียรติตามที่คาดไว้


1
ฉันคิดว่านี่ควรเป็นคำตอบมันใกล้กับคำขอ OP (ขอให้ใช้การตัด) วิธีนี้ช้ากว่าวิธี awk ประมาณ 5-10% (เนื่องจากมีอีกหนึ่งท่อที่ต้องจัดการกับ tr) แต่โดยทั่วไปจะไม่เกี่ยวข้อง
โอลิเวอร์

11

ฉันจะเสนอชื่อtr -s [:blank:]เป็นคำตอบที่ดีที่สุด

ทำไมเราต้องการใช้การตัด มันมีคำสั่งเวทย์มนตร์ที่บอกว่า "เราต้องการฟิลด์ที่สามและทุกฟิลด์หลังจากนั้นโดยเว้นสองฟิลด์แรก"

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

ฉันไม่เชื่อว่ามีคำสั่งที่เทียบเท่าสำหรับ awk หรือ perl split ซึ่งเราไม่ทราบว่าจะมีฟิลด์จำนวนเท่าใดเช่นใส่ฟิลด์ที่ 3 ผ่านฟิลด์ X


9

วิธีที่สั้นกว่า / เรียบง่ายกว่า: ใช้cuts(ตัดสเตียรอยด์ที่ฉันเขียน)

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

โปรดทราบว่าcutsดัชนีฟิลด์เป็นแบบศูนย์ดังนั้นฟิลด์ที่ 5 จึงถูกระบุเป็น 4

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

และสั้นกว่า (ไม่ได้ใช้การตัดเลย) คือ:

pgrep jboss

8

วิธีหนึ่งในการทำสิ่งนี้คือ:

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

เพื่อแทนที่ช่องว่างหลายช่องติดต่อกันด้วยช่องว่างเดียว


แปลกนี่ใช้ไม่ได้กับ OS X คำสั่ง sed ไม่เปลี่ยนช่องว่างหลายช่องเป็นหนึ่งช่องว่าง
rjurney

2
\sเป็นส่วนขยาย sed GNU ใน OS X คุณสามารถส่ง-Eแฟล็กไปที่ sed เพื่อเปิดใช้งานนิพจน์ทั่วไปที่ขยายเพิ่มจากนั้นใช้[[:space:]]แทน\sเช่น:sed -E 's/[[:space:]]+/ /g'
Jared Ng

4

โดยส่วนตัวฉันมักจะใช้ awk สำหรับงานแบบนี้ ตัวอย่างเช่น:

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

6
ที่สามารถอัดลงไปps axu | awk '/[j]boss/ {print $5}'ได้
zwol

1
ไม่ช้าลงอย่างเห็นได้ชัด (โดยเฉพาะอย่างยิ่งเมื่อมีกระบวนการอื่น ๆ ที่ฟุ่มเฟือย) จากนั้น sed / grep / cut
pihentagy

2

ในฐานะที่เป็นทางเลือกมี perl เสมอ:

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

หรือหากคุณต้องการให้ทุกฟิลด์เริ่มต้นที่ฟิลด์ # 3 (ตามที่ระบุในคำตอบข้อใดข้อหนึ่งข้างต้น):

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

ไม่ทำงานกับผลลัพธ์ของlsofฉันพยายามlsof|perl -lane 'print $F[5]'นี้บางครั้งรับคอลัมน์ที่ 5 บางครั้งที่ 6
rubo77

ฉันคิดว่าคำถามก็คือวิธีการใช้ตัวคั่นที่อาจมีจำนวนช่องว่างที่แตกต่างกัน เพื่อจุดประสงค์นี้คำตอบนั้นถูกต้อง
flitz

ในกรณีของปัญหาคือจำนวนคอลัมน์ไม่สอดคล้องกันในแต่ละแถว
flitz


2

หากคุณต้องการเลือกคอลัมน์จากเอาต์พุต ps เหตุผลใด ๆ ที่จะไม่ใช้ -o?

เช่น

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

ความกว้างคอลัมน์ขั้นต่ำที่จัดสรรไม่มีการเว้นช่องว่างคั่นเฉพาะช่องว่างเดียว

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 และ vsz ได้รับ 10 char width, 1 field field separator

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

ใช้ในสคริปต์: -

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

0

อีกวิธีถ้าคุณต้องใช้คำสั่ง cut

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

ใน Solaris เปลี่ยน awk ด้วยnawkหรือ/usr/xpg4/bin/awk


0

ฉันยังคงชอบวิธีที่ Perl จัดการกับเขตข้อมูลด้วยพื้นที่สีขาว
ฟิลด์แรกคือ $ F [0]

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

0

วิธีการของฉันคือการเก็บ PID แฟ้มใน / tmp และจะหากระบวนการที่เหมาะสมโดยใช้ตัวเลือกสำหรับการ-S sshนั่นอาจเป็นการใช้ในทางที่ผิด แต่ได้ผลสำหรับฉัน

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

วิธีที่ดีกว่าอาจเป็นการค้นหาที่SSH_PIDถูกต้องก่อนที่จะฆ่าเนื่องจากไฟล์อาจค้างและจะทำให้กระบวนการผิดพลาด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.