Grep có thể trả về true / false hay có các phương thức thay thế


130

Là một phần của tập lệnh này, tôi cần có thể kiểm tra xem đối số đầu tiên được đưa ra có khớp với từ đầu tiên của tệp không. Nếu có, thoát với một thông báo lỗi; nếu không, nối các đối số vào tệp. Tôi hiểu cách viết ifcâu lệnh, nhưng không biết cách sử dụng greptrong tập lệnh. Tôi hiểu rằng grepsẽ trông giống như thế này

grep ^$1 schemas.txt

Tôi cảm thấy như thế này sẽ dễ dàng hơn nhiều so với tôi đang làm nó.

Tôi nhận được một lỗi "quá nhiều đối số" trên ifcâu lệnh. Tôi đã thoát khỏi khoảng trống giữa grep -qvà sau đó có một toán tử nhị phân lỗi dự kiến.

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi

1
Mất [bài ]và nó sẽ hoạt động. Mặc dù bạn có thể muốn trích dẫn mô hình của mình:if grep -q "^$1" schemas.txt; then …
derobert

giải pháp một dòng sử dụng tính năng "Lệnh nhóm" của Bash: stackoverflow.com/questions/6550484/iêu
Trevor Boyd Smith

Câu trả lời:


186

greptrả về một mã thoát khác nếu nó tìm thấy thứ gì đó (không) so với nếu nó không tìm thấy gì (khác không). Trong một iftuyên bố, mã thoát không được ánh xạ thành "true" và mã thoát khác không được ánh xạ thành false. Ngoài ra, grep có một -qđối số để không xuất văn bản phù hợp (nhưng chỉ trả về mã trạng thái thoát)

Vì vậy, bạn có thể sử dụng grep như thế này:

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Một lưu ý nhanh, khi bạn làm một cái gì đó như thế if [ -z "$var" ]…, hóa ra đó [thực sự là một lệnh bạn đang chạy, giống như grep. Trên hệ thống của tôi, nó /usr/bin/[. (Chà, về mặt kỹ thuật, vỏ của bạn có thể được tích hợp sẵn, nhưng đó là một sự tối ưu hóa. Nó hoạt động như thể đó là một lệnh). Nó hoạt động theo cùng một cách, [trả về mã thoát bằng 0 cho true, mã thoát không khác cho false. ( testlà điều tương tự như [, ngoại trừ việc đóng cửa ])


Tại sao câu lệnh if không cần ngoặc? Tôi có nó làm việc mà không có, nhưng không hiểu tại sao. Tôi vẫn có thể lồng nó mà không có dấu ngoặc?
Lauren

@Lauren bạn có bỏ lỡ ghi chú nhanh không? [không phải là một phần của cú pháp if, về mặt khái niệm, đó là một lệnh bạn đang chạy, giống như grep
derobert

2
@Lauren Bạn không sử dụng grep bên trong [, bạn sử dụng cái này hay cái khác, tùy thuộc vào điều kiện bạn muốn kiểm tra. . không phải là một điều bình thường để làm
derobert

3
FYI, chạy ls -l /usr/bin/\[man [để xem đó [là một chương trình như bất kỳ chương trình nào khác, nó trông giống như một yếu tố cú pháp - điều này sẽ làm cho nó rõ ràng và dễ hiểu hơn. (để thuận tiện, [cũng là một tích hợp trong bash, dash và những thứ khác - nhưng nó vẫn là một lệnh). cũng thử type -all [trong bash.
cas

1
@AlexanderCska nếu bạn muốn grep in các dòng trùng khớp (ví dụ: để đặt chúng ở đâu đó), sau đó bỏ qua -q, tùy chọn đó sẽ bảo grep yên lặng (không in các dòng khớp).
derobert

48

Một cách đơn giản khác là sử dụng grep -c.

Đầu ra đó (không trả về dưới dạng mã thoát), số lượng dòng khớp với mẫu, vì vậy 0 nếu không có kết quả khớp hoặc 1 hoặc nhiều hơn nếu có kết quả khớp.

Vì vậy, nếu bạn muốn kiểm tra xem mẫu đó có khớp 3 lần trở lên không, bạn sẽ làm:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...

17
Chính xác hơn, nó sẽ xuất 1 nếu chỉ tìm thấy một lần. Để xuất 1 bất kể số lượng tìm thấy phù hợp sử dụng grep -cim1thay thế.
manatwork

Phương pháp này cũng có thể được sử dụng để phân biệt giữa lỗi grep và grep 'mẫu được tìm thấy 0 lần'. (mặc dù không phải với câu lệnh if chính xác được sử dụng, tôi nghĩ rằng một biến là bắt buộc)
Evan Benn

3

Tôi biết tôi đến trễ vì điều này, nhưng tôi thích phiên bản ngắn này:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt

0

Nếu chúng ta muốn bắt từ đầu tiên của tệp, chúng ta cần thêm -zwvào grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

Không có -zchúng tôi nhận được từ đầu tiên của một dòng. Không có -wchúng tôi nhận được một phần từ.


-2

Nếu bạn muốn sử dụng nó với dấu ngoặc vuông, bạn có thể thực hiện bên dưới

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

Logic này hoạt động cho tất cả các lệnh, Chỉ cần đặt các lệnh của bạn bên trong backtick (nút phía trên tab hoặc xuống nút Esc hoặc ở bên trái của nút 1)


1
Bạn cần trích dẫn `grep -q PATTERN file.txt`, nếu không, toán tử split + global được áp dụng và điều đó sẽ gây ra sự cố cho bất kỳ đầu ra nào chứa các ký tự $IFShoặc ký tự đại diện. Tổng quát hơn, [ "`cmd`" ]sẽ trả về true nếu cmdxuất ra ít nhất một dòng không trống trên thiết bị xuất chuẩn (với các vấn đề tiềm ẩn nếu nó xuất ra các byte NUL). Điều đó có nghĩa là shell sẽ phải lưu trữ toàn bộ đầu ra trong bộ nhớ và chờ cho nó kết thúc. Sử dụng if cmd | grep -q .thay thế có thể được ưa thích hơn trong vấn đề đó.
Stéphane Chazelas

Lệnh này sẽ không có ý nghĩa gì cả. Mục đích của công -qtắc là triệt tiêu grep đầu ra. Bạn đang nói: Kiểm tra MẪU trong file.txt, chặn bất kỳ đầu ra nào, sau đó đặt trạng thái trả về theo liệu có tìm thấy MẪU hay không. Sau đó, bỏ qua trạng thái trả về, lấy đầu ra lệnh (mà chúng tôi buộc phải trống), áp dụng phân tách từ và mở rộng toàn cầu tệp (dẫn đến không có đối số nào), sau đó chạy lệnh [(aka test) với chính xác một đối số - cụ thể là , ]- và sau đó, vì điều đó sẽ dẫn đến một lỗi, tiếng vang "không tìm thấy". @ StéphaneChazelas, tôi có bỏ lỡ điều gì không?
tự đại diện

1
@Wildcard, bạn nói đúng, tôi dường như đã bỏ qua -q. Nhận xét đó sẽ có ý nghĩa đối với [ `grep PATTERN file.txt ` ], nhưng như được gợi ý trong nhận xét, [ "`grep -n PATTERN file.txt`" ]sẽ tốt hơn nếu THỰC SỰ chỉ có thể khớp với các dòng trống. Mặc dù ở đây tất nhiên là if grep -q PATTERN file.txtbạn muốn.
Stéphane Chazelas
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.