Làm thế nào để kiểm tra nếu chuỗi tồn tại trong tệp với Bash?


337

Tôi có một tập tin chứa tên thư mục:

my_list.txt :

/tmp
/var/tmp

Tôi muốn kiểm tra Bash trước khi tôi thêm tên thư mục nếu tên đó đã tồn tại trong tệp.


Để tìm tất cả các chuỗi trong một tệp, bạn có thể chạy grep trong vòng lặp FOR: unix.stackexchange.com/a/462445/43233
Noam Manos

Câu trả lời:


654
grep -Fxq "$FILENAME" my_list.txt

Trạng thái thoát là 0 (đúng) nếu tên được tìm thấy, 1 (sai) nếu không, vì vậy:

if grep -Fxq "$FILENAME" my_list.txt
then
    # code if found
else
    # code if not found
fi

Giải trình

Dưới đây là các phần có liên quan của trang man chogrep :

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        Giải thích MẪU như một danh sách các chuỗi cố định, được phân tách bằng các dòng mới, bất kỳ chuỗi nào sẽ được khớp.

-x, --line-regexp

        Chỉ chọn những trận đấu khớp chính xác với toàn bộ dòng.

-q, --quiet,--silent

        Yên tĩnh; không ghi bất cứ điều gì vào đầu ra tiêu chuẩn. Thoát ngay lập tức với trạng thái 0 nếu tìm thấy bất kỳ kết quả khớp nào, ngay cả khi phát hiện ra lỗi. Cũng xem tùy chọn -shoặc --no-messages.

Xử lý lỗi

Như đã chỉ ra một cách đúng đắn trong các ý kiến, cách tiếp cận trên âm thầm xử lý các trường hợp lỗi như thể tìm thấy chuỗi. Nếu bạn muốn xử lý lỗi theo một cách khác, bạn sẽ phải bỏ qua -qtùy chọn và phát hiện lỗi dựa trên trạng thái thoát:

Thông thường, trạng thái thoát là 0 nếu các dòng được chọn được tìm thấy và 1 nếu không. Nhưng trạng thái thoát là 2 nếu xảy ra lỗi, trừ khi -qhoặc --quiethoặc --silenttùy chọn được sử dụng và tìm thấy một dòng được chọn. Lưu ý, tuy nhiên, POSIX chỉ nhiệm vụ, đối với các chương trình như grep, cmpdiff, rằng trạng thái thoát trong trường hợp lỗi lớn hơn 1; do đó, vì lợi ích của tính di động, nên sử dụng logic kiểm tra điều kiện chung này thay vì bình đẳng nghiêm ngặt với 2.

Để chặn đầu ra bình thường từ grep, bạn có thể chuyển hướng nó đến /dev/null. Lưu ý rằng lỗi tiêu chuẩn vẫn không bị ảnh hưởng, do đó, bất kỳ thông báo lỗi nào grepcó thể in sẽ kết thúc trên bảng điều khiển như bạn có thể muốn.

Để xử lý ba trường hợp, chúng ta có thể sử dụng một casetuyên bố:

case `grep -Fx "$FILENAME" "$LIST" >/dev/null; echo $?` in
  0)
    # code if found
    ;;
  1)
    # code if not found
    ;;
  *)
    # code if an error occurred
    ;;
esac

2
Nếu tôi thực thi lệnh này từ bash script, làm thế nào để bắt 0 hoặc 1 vào một biến?
Toren

6
@Toren Hầu hết các trạng thái thoát gần đây có thể được truy cập bằng cách sử dụng $?. bạn cũng có thể sử dụng lệnh grep bên cạnh ifcâu lệnh (như thể hiện trong câu trả lời được cập nhật).
Shawn Chin

5
Bạn có thể sử dụng grep -Fqx "$FILENAME"và bạn không phải lo lắng về các ký tự regex trong nội dung biến và bạn sẽ không phải sử dụng chúng trong chuỗi tìm kiếm.
Tạm dừng cho đến khi có thông báo mới.

4
Một vài lưu ý cho mọi người khi xem câu trả lời này: 1) Trong bash, 0 luôn luôn đúng và mọi thứ khác luôn sai 2) Chỉ sử dụng cờ -x nếu bạn muốn toàn bộ dòng khớp chính xác. Nếu bạn chỉ muốn tìm xem chuỗi của bạn có tồn tại trong tệp hay không, hãy bỏ qua nó. Nếu bạn muốn tìm xem chuỗi của bạn có tồn tại chính xác nhưng không khớp với toàn bộ một dòng nhất thiết không (nghĩa là toàn bộ từ), hãy sử dụng -w.
Schmick

1
Tôi không nhận -q / --silentđược nó là cần thiết? Nó nói sai "tất cả tốt" cho bash ngay cả khi có lỗi xảy ra. Nếu tôi hiểu điều đó một cách chính xác. Có vẻ là một khái niệm thiếu sót cho trường hợp này.
redanimalwar

90

Về giải pháp sau:

grep -Fxq "$FILENAME" my_list.txt

Trong trường hợp bạn đang tự hỏi (như tôi đã làm) -Fxqcó nghĩa là gì trong tiếng Anh đơn giản:

  • F: Ảnh hưởng đến cách THỰC HIỆN được diễn giải (chuỗi cố định thay vì biểu thức chính quy)
  • x: Khớp toàn bộ dòng
  • q: Shhhhh ... in tối thiểu

Từ tập tin người đàn ông:

-F, --fixed-strings
    Interpret  PATTERN  as  a  list of fixed strings, separated by newlines, any of which is to be matched.
    (-F is specified by POSIX.)
-x, --line-regexp
    Select only those matches that exactly match the whole line.  (-x is specified by POSIX.)
-q, --quiet, --silent
    Quiet; do not write anything to standard output.  Exit immediately with zero status  if  any  match  is
          found,  even  if  an error was detected.  Also see the -s or --no-messages option.  (-q is specified by
          POSIX.)

5
-F không ảnh hưởng đến việc xử lý tập tin, nó ảnh hưởng đến cách diễn giải MẪU. Thông thường, MẪU được hiểu là một biểu thức chính quy, nhưng với -F, nó sẽ được hiểu là một chuỗi cố định.
Adam S

41

Ba phương pháp trong tâm trí tôi:

1) Kiểm tra ngắn cho một tên trong một đường dẫn (Tôi không chắc đây có thể là trường hợp của bạn)

ls -a "path" | grep "name"


2) Kiểm tra ngắn cho một chuỗi trong một tệp

grep -R "string" "filepath"


3) Tập lệnh bash dài hơn bằng regex:

#!/bin/bash

declare file="content.txt"
declare regex="\s+string\s+"

declare file_content=$( cat "${file}" )
if [[ " $file_content " =~ $regex ]] # please note the space before and after the file content
    then
        echo "found"
    else
        echo "not found"
fi

exit

Điều này sẽ nhanh hơn nếu bạn phải kiểm tra nhiều chuỗi trên một nội dung tệp bằng cách sử dụng một vòng lặp, ví dụ như thay đổi regex tại bất kỳ cicle nào.


10
Tại sao các khoảng trắng cần thiết trước và sau $ file_contenet?
EminezArtus 3/2/2015

Cộng 1 cho giải pháp nhanh và tổng quát hơn
Wassadamo

19

Cách đơn giản hơn:

if grep "$filename" my_list.txt > /dev/null
then
   ... found
else
   ... not found
fi

Mẹo: gửi đến /dev/nullnếu bạn muốn trạng thái thoát lệnh, nhưng không xuất ra.


1
hoặc sử dụng -qgiống như --quiet:)
rogerdpack

đồng ý về -qcâu trả lời tốt nhất ở đây, và là vị trí thứ tư. không có công lý trong thế giới này.
tatsu

14

Cách dễ nhất và đơn giản nhất sẽ là:

isInFile=$(cat file.txt | grep -c "string")


if [ $isInFile -eq 0 ]; then
   #string not contained in file
else
   #string is in file at least once
fi

grep -c sẽ trả về số lần chuỗi xảy ra trong tệp.


5

Nếu tôi hiểu chính xác câu hỏi của bạn, điều này sẽ làm những gì bạn cần.

  1. bạn có thể chỉ định thư mục bạn muốn thêm thông qua biến kiểm tra $
  2. nếu thư mục đã có trong danh sách, đầu ra là "dir đã được liệt kê"
  3. nếu thư mục chưa có trong danh sách, nó sẽ được thêm vào my_list.txt

Trong một dòng :check="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt


Bạn không cần phải kiểm tra đầu ra của grep, bạn chỉ có thể sử dụng grep -qvà gọi grep trực tiếp từ ifcâu trả lời của Thomas. Ngoài ra, câu hỏi không bao gồm kiểm tra xem thư mục có tồn tại hay không trước khi thêm nó vào danh sách (rốt cuộc đó có thể là danh sách các thư mục bị xóa).
Bọ Cạp

Tôi đã xóa đoạn script ví dụ, nó không thêm bất cứ điều gì vào câu trả lời do Thomas đưa ra.
lecodesportif

3

Nếu bạn chỉ muốn kiểm tra sự tồn tại của một dòng, bạn không cần tạo tệp. Ví dụ,

if grep -xq "LINE_TO_BE_MATCHED" FILE_TO_LOOK_IN ; then
  # code for if it exists
else
  # code for if it does not exist
fi  

3

Phiên bản của tôi sử dụng fgrep

  FOUND=`fgrep -c "FOUND" $VALIDATION_FILE`
  if [ $FOUND -eq 0 ]; then
    echo "Not able to find"
  else
    echo "able to find"     
  fi  

Tôi không thấy -ctùy chọn trongfgrep --help
Nam G VU

3
grep -E "(string)" /path/to/file || echo "no match found"

Tùy chọn -E làm cho grep sử dụng các biểu thức thông thường


1

Giải pháp của @ Thomas không hoạt động với tôi vì một số lý do nhưng tôi có chuỗi dài hơn với các ký tự và khoảng trắng đặc biệt nên tôi chỉ thay đổi các tham số như thế này:

if grep -Fxq 'string you want to find' "/path/to/file"; then
    echo "Found"
else
    echo "Not found"
fi

Hy vọng nó sẽ giúp được ai đó



0
grep -Fxq "String to be found" | ls -a
  • grep sẽ giúp bạn kiểm tra nội dung
  • ls sẽ liệt kê tất cả các tập tin

Tôi không nghĩ rằng lschấp nhận đầu vào tiêu chuẩn?
Thom Wiggers

@ThomWiggers Tôi đã thử tương tự và nó hoạt động với tôi.
Shinoy Shaji

-1
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi
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.