Tại sao `grep -v` này không hoạt động như mong đợi?


12

Tôi có một vấn đề lạ liên quan đến grep -vtruy vấn. Cho phép tôi giải thích:

Để hiển thị các kết nối tôi sử dụng 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)

Hiện tại ttycủa thiết bị đầu cuối của tôi làpts/0

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

Tôi cố gắng loại trừ kết nối của riêng tôi bằng cách sử dụng grep -v $(tty | cut -f3-4 -d'/'). Đầu ra dự kiến ​​của lệnh này sẽ whokhông có kết nối của tôi. Tuy nhiên, đầu ra là bất ngờ nhất:

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

Tôi gửi kèm theo $(...)dấu ngoặc kép và điều đó dường như khắc phục vấn đề "Không có tệp hoặc thư mục như vậy". Tuy nhiên, kết nối của tôi vẫn được in ngay cả khi tty ( pts/0) của tôi đã bị loại trừ:

$ 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)

Về điểm này, tôi hoàn toàn không biết tại sao greptruy vấn bị trục trặc.


4
Làm thế nào về việc sử dụng set -xđầu tiên ... Sau đó chạy lệnh của bạn và xem những gì bạn đang thực sự cố gắng grep...
don_crissti

@don_crissti ah, tôi hiểu rồi; nó nói với tôi rằng tôi thực sự đang grep"không phải là một tty". Làm thế nào bạn có thể đề nghị tôi nhận được xung quanh này?
lẽ là

Câu trả lời:


18

Zachary đã giải thích nguồn gốc của vấn đề.

Trong khi bạn có thể làm việc xung quanh nó với

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

Điều đó sẽ sai, ví dụ nếu tty đó pts/1, bạn sẽ loại trừ tất cả các dòng có chứa pts/10. Một số greptriển khai có một -wtùy chọn để thực hiện tìm kiếm từ

who | grep -vw pts/1

sẽ không khớp pts/10bởi vì pts/1trong đó không có ký tự không có từ.

Hoặc bạn có thể sử dụng awkđể lọc theo giá trị chính xác của trường thứ hai như:

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

Nếu bạn muốn làm điều đó trong một lệnh:

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

Các stdin ban đầu được sao chép vào mô tả tập tin 3 và được khôi phục cho ttylệnh.


3
+1 để tìm ra cách thực hiện trong một lệnh và chỉ ra lỗi đó.
Zachary Brady

Thêm một lót nữa:tty | cut -f3-4 -d'/' | xargs -I % sh -c "who | grep -v %"
axxis 8/12/2016

20

Từ trang thông tin tty.

'tty' in tên tệp của thiết bị đầu cuối được kết nối với đầu vào tiêu chuẩn của nó. Nó in 'không phải là một tty' nếu đầu vào tiêu chuẩn không phải là một thiết bị đầu cuối.

Vấn đề là trong ví dụ của bạn, stdin của tty là một đường ống chứ không phải thiết bị đầu cuối của bạn.

Bạn có thể thấy từ ví dụ này.

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

Để làm việc xung quanh mà bạn có thể làm một cái gì đó như thế này.

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

Có một cách nhanh hơn / hiệu quả hơn tuy nhiên nó đòi hỏi hai lệnh.

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

@Christopher bạn là người duy nhất đăng nhập vào máy tính của bạn?
Zachary Brady

@Christopher, lạ. Vì vậy, who | grep -v "$(ps ax | grep "^$$" | awk '{ print $2 }')"sản xuất sản lượng dự kiến ​​trên hộp của tôi và t=$(tty) who|grep -v "${t:5}"không sản xuất gì.
Zachary Brady

Bạn đang sử dụng shell / phiên bản nào? GNU bash, version 4.1.2
Zachary Brady

2
ps ax | grep "^ *$$"có thể khớp sai, ví dụ: vỏ của bạn là 123 và 1234 tồn tại; ps ax -otty= $$mạnh mẽ hơn và chỉ có một quá trình. Nhưng tôi thích (hoặc ) ${t:5}của bạn ${t#/dev/}(hoặc substr(t,6))
dave_thndry_085

1
Xin đừng thêm từ chối. Trong khi ý định là đáng khen ngợi, họ không thực sự giúp câu trả lời. Nếu ai đó chỉ ra một lỗ hổng trong câu trả lời của bạn, chỉ cần chỉnh sửa câu trả lời của bạn để kết hợp chỉnh sửa.
terdon
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.