Cách tốt
Thông thường bạn không thể làm điều này với grep nhưng bạn có thể sử dụng các công cụ khác. AWK đã được đề cập nhưng bạn cũng có thể sử dụng sed
, như thế này:
sed -e '1p' -e '/youpattern/!d'
Làm thế nào nó hoạt động:
Tiện ích sed hoạt động trên từng dòng riêng lẻ, chạy các lệnh được chỉ định trên mỗi dòng. Bạn có thể có nhiều lệnh, chỉ định một số -e
tùy chọn. Chúng ta có thể thêm trước mỗi lệnh với một tham số phạm vi chỉ định xem lệnh này có nên được áp dụng cho dòng cụ thể hay không.
"1p" là lệnh đầu tiên. Nó sử dụng p
lệnh thường in tất cả các dòng. Nhưng chúng tôi cung cấp cho nó một giá trị số chỉ định phạm vi cần áp dụng. Ở đây, chúng tôi sử dụng 1
có nghĩa là dòng đầu tiên. Nếu bạn muốn in nhiều dòng, bạn có thể sử dụng x,yp
mà x
là dòng đầu tiên để in, y
là dòng cuối cùng để in. Ví dụ để in 3 dòng đầu tiên, bạn sẽ sử dụng1,3p
Lệnh tiếp theo d
thường xóa tất cả các dòng khỏi bộ đệm. Trước lệnh này, chúng tôi đặt yourpattern
giữa hai /
ký tự. Đây là một cách khác (đầu tiên là xác định dòng nào như chúng ta đã làm với p
lệnh) của các dòng địa chỉ mà lệnh sẽ chạy. Điều này có nghĩa là lệnh sẽ chỉ hoạt động cho các dòng phù hợp yourpattern
. Ngoại trừ, chúng tôi sử dụng !
ký tự trước khi d
lệnh đảo ngược logic của nó. Vì vậy, bây giờ nó sẽ loại bỏ tất cả các dòng không khớp với mẫu đã chỉ định.
Cuối cùng, sed sẽ in tất cả các dòng còn lại trong bộ đệm. Nhưng chúng tôi đã xóa các dòng không khớp với bộ đệm để chỉ các dòng phù hợp sẽ được in.
Để tổng hợp: chúng tôi in dòng thứ 1, sau đó chúng tôi xóa tất cả các dòng không khớp với mẫu của chúng tôi khỏi đầu vào. Phần còn lại của dòng được in (để chỉ dòng mà làm phù hợp với mô hình).
Vấn đề đầu tiên
Như đã đề cập trong các ý kiến, có một vấn đề với phương pháp này. Nếu mẫu được chỉ định khớp với dòng đầu tiên, nó sẽ được in hai lần (một lần theo p
lệnh và một lần vì khớp). Chúng ta có thể tránh điều này theo hai cách:
Thêm 1d
lệnh sau 1p
. Như tôi đã đề cập, d
lệnh xóa các dòng khỏi bộ đệm và chúng tôi chỉ định phạm vi của nó theo số 1, có nghĩa là nó sẽ chỉ xóa dòng thứ nhất. Vì vậy, lệnh sẽ làsed -e '1p' -e '1d' -e '/youpattern/!d'
Sử dụng 1b
lệnh, thay vì 1p
. Đó là một mẹo. b
lệnh cho phép chúng ta chuyển sang lệnh khác được chỉ định bởi nhãn (cách này có thể bỏ qua một số lệnh). Nhưng nếu nhãn này không được chỉ định (như trong ví dụ của chúng tôi), nó chỉ nhảy đến cuối các lệnh, bỏ qua các lệnh còn lại cho dòng của chúng tôi. Vì vậy, trong trường hợp của chúng tôi, d
lệnh cuối cùng sẽ không xóa dòng này khỏi bộ đệm.
Ví dụ đầy đủ:
ps aux | sed -e '1b' -e '/syslog/!d'
Sử dụng dấu chấm phẩy
Một số sed
triển khai có thể giúp bạn tiết kiệm một số thao tác gõ bằng cách sử dụng dấu chấm phẩy để phân tách các lệnh thay vì sử dụng nhiều -e
tùy chọn. Vì vậy, nếu bạn không quan tâm đến việc di động, lệnh sẽ là ps aux | sed '1b;/syslog/!d'
. Nó hoạt động ít nhất trong GNU sed
và busybox
thực hiện.
Cách điên
Tuy nhiên, đây là cách khá điên rồ để làm điều này với grep. Nó chắc chắn không tối ưu, tôi đang đăng bài này chỉ cho mục đích học tập, nhưng bạn có thể sử dụng nó chẳng hạn, nếu bạn không có bất kỳ công cụ nào khác trong hệ thống của mình:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'
Làm thế nào nó hoạt động
Đầu tiên, chúng tôi sử dụng -n
tùy chọn để thêm số dòng trước mỗi dòng. Chúng tôi muốn đánh số tất cả các dòng chúng tôi phù hợp .*
- bất cứ điều gì, thậm chí cả dòng trống. Theo đề xuất trong các nhận xét, chúng tôi cũng có thể khớp '^', kết quả là như nhau.
Sau đó, chúng tôi đang sử dụng các biểu thức chính quy mở rộng để chúng tôi có thể sử dụng \|
ký tự đặc biệt hoạt động như OR. Vì vậy, chúng tôi khớp nếu dòng bắt đầu bằng 1:
(dòng đầu tiên) hoặc chứa mẫu của chúng tôi (trong trường hợp này là dòng syslog
).
Vấn đề về số dòng
Bây giờ vấn đề là, chúng tôi đang nhận được số dòng xấu xí này trong đầu ra của chúng tôi. Nếu đây là một vấn đề, chúng ta có thể loại bỏ chúng bằng cut
, như thế này:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-
-d
tùy chọn chỉ định dấu phân cách, -f
chỉ định các trường (hoặc cột) mà chúng tôi muốn in. Vì vậy, chúng tôi muốn cắt từng dòng trên mỗi :
ký tự và chỉ in 2 và tất cả các cột tiếp theo. Điều này có hiệu quả loại bỏ cột đầu tiên với dấu phân cách và đây chính xác là những gì chúng ta cần.
ack
rất hữu ích, và tại saoperl
quá khứ vọtsed
,awk
vv phổ biến: điều quan trọng là cho các bộ phận để tổng hợp thành một tổng thể chặt chẽ.