ทำไม `grep -v 'ถึงไม่ทำงานอย่างที่คาดไว้


12

ฉันมีปัญหาแปลก ๆ เกี่ยวกับgrep -vข้อความค้นหา ให้ฉันอธิบาย:

ในการแสดงการเชื่อมต่อฉันใช้who:

$ who
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

กระแสttyของเทอร์มินัลของฉันคือpts/0

$ tty
/dev/pts/0
$ tty | cut -f3-4 -d'/'
pts/0

grep -v $(tty | cut -f3-4 -d'/')ผมพยายามที่จะไม่รวมการเชื่อมต่อของตัวเองโดยใช้ ผลลัพธ์ที่คาดหวังของคำสั่งนี้ควรจะเป็นwhoโดยไม่ต้องเชื่อมต่อของฉัน อย่างไรก็ตามผลลัพธ์ไม่คาดคิดมากที่สุด:

$ who | grep -v $(tty | cut -f3-4 -d'/')
grep: a: No such file or directory
grep: tty: No such file or directory

ฉันใส่$(...)เครื่องหมายคำพูดในและดูเหมือนว่าจะแก้ไขปัญหา "ไม่มีไฟล์หรือไดเรกทอรี" อย่างไรก็ตามการเชื่อมต่อของฉันยังคงถูกพิมพ์แม้ว่า tty ( pts/0) ของฉันควรถูกแยกออก:

$ who | grep -v "$(tty | cut -f3-4 -d'/')"
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

ณ จุดนี้ฉันไม่รู้ว่าทำไมการgrepค้นหาจึงทำงานผิดปกติ


4
วิธีการเกี่ยวกับการใช้set -xครั้งแรก ... จากนั้นเรียกใช้คำสั่งของคุณและดูสิ่งที่คุณพยายามที่จะgrep...
don_crissti

@don_crissti อ่าเข้าใจแล้ว มันกำลังบอกฉันว่าฉันgrepไม่ใช่ "tty" คุณจะแนะนำให้ฉันแก้ไขสิ่งนี้อย่างไร
อาจจะเป็น

คำตอบ:


18

Zachary ได้อธิบายสาเหตุของปัญหา

ในขณะที่คุณสามารถหลีกเลี่ยงได้ด้วย

tty=$(tty)
tty_without_dev=${tty#/dev/}
who | grep -v "$tty_without_dev"

ว่าจะมีความผิดเป็นตัวอย่างเช่นถ้า TTY ที่เป็นคุณจะจบลงไม่รวมสายทั้งหมดที่มีpts/1 การใช้งานpts/10บางอย่างgrepมี-wตัวเลือกในการค้นหาคำ

who | grep -vw pts/1

จะไม่ตรงกันpts/10เนื่องจากpts/1ในนั้นไม่ได้ตามด้วยอักขระที่ไม่ใช่คำ

หรือคุณสามารถใช้awkเพื่อกรองมูลค่าที่แน่นอนของเขตข้อมูลที่สองเช่น:

who | awk -v "tty=$tty_without_dev" '$2 != tty'

หากคุณต้องการที่จะทำมันในหนึ่งคำสั่ง:

{ who | awk -v "tty=$(tty<&3)" '$2 != substr(tty,6)'; } 3<&0

stdin ดั้งเดิมถูกทำซ้ำลงใน file descriptor 3 และเรียกคืนสำหรับttyคำสั่ง


3
+1 สำหรับการหาวิธีการในหนึ่งคำสั่งและชี้ให้เห็นข้อผิดพลาดนั้น
Zachary Brady

อีกหนึ่งสายการบิน:tty | cut -f3-4 -d'/' | xargs -I % sh -c "who | grep -v %"
axxis

20

จากหน้าข้อมูล tty

'tty' พิมพ์ชื่อไฟล์ของเครื่องที่เชื่อมต่อกับอินพุตมาตรฐาน มันพิมพ์ `ไม่ใช่ tty 'ถ้าอินพุตมาตรฐานไม่ใช่เทอร์มินัล

ปัญหาคือว่าในตัวอย่าง stty ของคุณคือท่อไม่ใช่เทอร์มินัลของคุณ

คุณสามารถดูได้จากตัวอย่างนี้

$ tty
/dev/pts/29
$ echo | tty 
not a tty

ในการหลีกเลี่ยงสิ่งนั้นคุณสามารถทำสิ่งนี้ได้

who | grep -wv "$(ps ax | awk "\$1 == $$ {print \$2}" )"

มีวิธีที่เร็วขึ้น / มีประสิทธิภาพมากขึ้นอย่างไรก็ตามมันต้องใช้สองคำสั่ง

t=$(tty)
who|grep -wv "${t:5}"

@Christopher คุณเป็นคนเดียวที่เข้าสู่ระบบคอมพิวเตอร์ของคุณ?
Zachary Brady

@ คริสโตเฟอร์แปลก ๆ ดังนั้นwho | grep -v "$(ps ax | grep "^$$" | awk '{ print $2 }')"ผลิตผลที่คาดหวังในกล่องของฉันและt=$(tty) who|grep -v "${t:5}"ผลิตอะไร
Zachary Brady

คุณใช้เชลล์ / รุ่นอะไร GNU bash, version 4.1.2
Zachary Brady

2
ps ax | grep "^ *$$"สามารถจับคู่แบบเท็จได้เช่นเชลล์ของคุณคือ 123 และ 1234; ps ax -otty= $$แข็งแกร่งกว่าและมีเพียงกระบวนการเดียวเท่านั้น แต่ฉันชอบของคุณ${t:5}หรือ Stephane ${t#/dev/}(หรือsubstr(t,6))
dave_thompson_085

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