Bagaimana cara menguji apakah string ada dalam file dengan Bash?


337

Saya memiliki file yang berisi nama direktori:

my_list.txt :

/tmp
/var/tmp

Saya ingin memeriksa di Bash sebelum saya akan menambahkan nama direktori jika nama itu sudah ada di file.


Untuk menemukan semua string di dalam file, Anda dapat menjalankan grep di loop FOR: unix.stackexchange.com/a/462445/43233
Noam Manos

Jawaban:


655
grep -Fxq "$FILENAME" my_list.txt

Status keluar adalah 0 (benar) jika nama itu ditemukan, 1 (salah) jika tidak, jadi:

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

Penjelasan

Berikut adalah bagian yang relevan dari halaman manual untukgrep :

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        Menafsirkan POLA sebagai daftar string tetap, dipisahkan oleh baris baru, yang mana saja yang harus dicocokkan.

-x, --line-regexp

        Pilih hanya yang cocok persis dengan seluruh baris.

-q, --quiet,--silent

        Diam; jangan menulis apa pun ke output standar. Segera keluar dengan status nol jika ada kecocokan yang ditemukan, bahkan jika kesalahan terdeteksi. Lihat juga opsi -satau --no-messages.

Menangani kesalahan

Sebagaimana ditunjukkan dalam komentar, pendekatan di atas diam-diam memperlakukan kasus kesalahan seolah-olah string ditemukan. Jika Anda ingin menangani kesalahan dengan cara yang berbeda, Anda harus menghilangkan -qopsi, dan mendeteksi kesalahan berdasarkan status keluar:

Biasanya, status keluar adalah 0 jika baris yang dipilih ditemukan dan 1 sebaliknya. Tetapi status keluar adalah 2 jika kesalahan terjadi, kecuali jika opsi -qatau --quietatau --silentdigunakan dan baris yang dipilih ditemukan. Catatan, bagaimanapun, bahwa POSIX hanya mandat, untuk program-program seperti grep, cmp, dan diff, bahwa status exit terjadi error lebih besar dari 1; Oleh karena itu disarankan, demi portabilitas, untuk menggunakan logika yang menguji kondisi umum ini alih-alih kesetaraan ketat dengan 2.

Untuk menekan output normal grep, Anda dapat mengarahkan ulang ke /dev/null. Perhatikan bahwa kesalahan standar tetap tidak terarah, sehingga pesan kesalahan yang grepmungkin dicetak akan berakhir di konsol seperti yang Anda inginkan.

Untuk menangani tiga kasus, kita dapat menggunakan casepernyataan:

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
Jika saya menjalankan perintah ini dari skrip bash bagaimana cara menangkap 0 atau 1 menjadi variabel?
Toren

6
@ Toren Sebagian besar status keluar terakhir dapat diakses menggunakan $?. Anda juga dapat menggunakan perintah grep di samping ifpernyataan (seperti yang ditunjukkan pada jawaban yang diperbarui).
Shawn Chin

5
Anda dapat menggunakan grep -Fqx "$FILENAME"dan Anda tidak perlu khawatir tentang karakter regex dalam konten variabel dan Anda tidak harus menggunakannya dalam string pencarian.
Dijeda sampai pemberitahuan lebih lanjut.

4
Beberapa catatan untuk orang-orang yang mencari jawaban ini: 1) Dalam bash, 0 selalu benar dan yang lainnya selalu salah 2) Hanya menggunakan flag -x jika Anda ingin seluruh baris cocok persis. Jika Anda hanya ingin mengetahui apakah string Anda ada di file sama sekali, biarkan saja. Jika Anda ingin mengetahui apakah string Anda benar-benar ada tetapi tanpa mencocokkan seluruh baris (misalnya, sebagai keseluruhan kata), gunakan -w.
Schmick

1
Saya tidak mengerti -q / --silentapakah ini dibutuhkan? Itu salah mengatakan "semua baik" untuk bash bahkan jika kesalahan terjadi. Jika saya mendapatkannya dengan benar. Tampaknya konsep yang cacat untuk kasus ini.
redanimalwar

90

Mengenai solusi berikut:

grep -Fxq "$FILENAME" my_list.txt

Jika Anda bertanya-tanya (seperti yang saya lakukan) apa -Fxqartinya dalam bahasa Inggris yang sederhana:

  • F: Mempengaruhi bagaimana POLA ditafsirkan (string tetap bukan suatu regex)
  • x: Cocokkan seluruh baris
  • q: Shhhhh ... pencetakan minimal

Dari file man:

-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 tidak mempengaruhi pemrosesan file, itu mempengaruhi bagaimana POLA ditafsirkan. Biasanya, POLA ditafsirkan sebagai regex, tetapi dengan -F akan ditafsirkan sebagai string tetap.
Adam S

41

Tiga metode dalam pikiran saya:

1) Tes singkat untuk nama di jalur (Saya tidak yakin ini mungkin kasus Anda)

ls -a "path" | grep "name"


2) Tes singkat untuk string dalam file

grep -R "string" "filepath"


3) Skrip bash yang lebih panjang menggunakan 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

Ini harus lebih cepat jika Anda harus menguji beberapa string pada konten file menggunakan loop misalnya mengubah regex di setiap siklus.


10
Mengapa spasi diperlukan sebelum dan sesudah $ file_contenet?
EminezArtus

Plus 1 untuk solusi cepat dan yang lebih umum
Wassadamo

19

Cara yang lebih sederhana:

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

Tip: kirim ke /dev/nulljika Anda ingin status keluar perintah, tetapi bukan keluaran.


1
atau gunakan -qyang sama seperti --quiet:)
rogerdpack

setujui -qjuga jawaban terbaik di sini, dan di tempat keempat. tidak ada keadilan di dunia ini.
tatsu

15

Cara termudah dan paling sederhana adalah:

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 akan mengembalikan hitungan berapa kali string muncul dalam file.


5

Jika saya memahami pertanyaan Anda dengan benar, ini harus melakukan apa yang Anda butuhkan.

  1. Anda dapat menentukan direktori yang ingin Anda tambahkan melalui variabel $ check
  2. jika direktori sudah ada dalam daftar, hasilnya "dir sudah terdaftar"
  3. jika direktori belum ada dalam daftar, itu ditambahkan ke my_list.txt

Dalam satu baris :check="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt


Anda tidak perlu menguji keluaran grep, Anda cukup menggunakan grep -qdan memanggil grep langsung ifseperti yang dilakukan Thomas dalam jawabannya. Selain itu, pertanyaannya tidak termasuk memeriksa apakah direktori tersebut ada sebelum menambahkannya ke daftar (setelah semua, itu bisa menjadi daftar direktori yang dihapus).
sorpigal

Saya menghapus contoh skrip, itu tidak menambahkan apa pun ke jawaban yang diberikan oleh Thomas.
lecodesportif

3

Jika Anda hanya ingin memeriksa keberadaan satu baris, Anda tidak perlu membuat file. Misalnya,

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

Versi saya menggunakan fgrep

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

Saya tidak melihat -copsi difgrep --help
Nam G VU

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

Opsi -E membuat grep menggunakan ekspresi reguler


1

Solusi @ Thomas tidak bekerja untuk saya untuk beberapa alasan tetapi saya memiliki string yang lebih panjang dengan karakter khusus dan spasi putih jadi saya hanya mengubah parameter seperti ini:

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

Semoga ini bisa membantu seseorang



0
grep -Fxq "String to be found" | ls -a
  • grep akan membantu Anda memeriksa konten
  • ls akan mencantumkan semua File

@ThomWiggers Saya mencoba yang sama dan berhasil untuk saya
Shinoy Shaji

-1
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.