Bash dosyasında dize olup olmadığını nasıl test edebilirim?


337

Dizin adlarını içeren bir dosya var:

my_list.txt :

/tmp
/var/tmp

Dosyada bu ad zaten varsa bir dizin adı eklemeden önce Bash'a check-in yapmak istiyorum.


Bir dosyanın içindeki tüm dizeleri bulmak için grep komutunu
Noam Manos

Yanıtlar:


655
grep -Fxq "$FILENAME" my_list.txt

Ad bulunursa çıkış durumu 0 (true), değilse 1 (false) olur, bu nedenle:

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

açıklama

Man sayfasınıngrep ilgili bölümleri :

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        PATTERN'i, herhangi biri eşlenecek olan yeni satırlarla ayrılmış sabit dizelerin bir listesi olarak yorumlayın.

-x, --line-regexp

        Yalnızca tüm çizgiyle tam olarak eşleşen maçları seçin.

-q, --quiet,--silent

        Sessiz; standart çıktıya hiçbir şey yazmayın. Herhangi bir eşleşme bulunursa, bir hata tespit edilse bile hemen sıfır durumuyla çıkın. Ayrıca -sveya --no-messagesseçeneğine bakın.

Hata yönetimi

Yorumlarda doğru bir şekilde belirtildiği gibi, yukarıdaki yaklaşım hata durumlarını sessizce dize bulunmuş gibi ele alır. Hataları farklı bir şekilde işlemek istiyorsanız, -qseçeneği atlamanız ve hataları çıkış durumuna göre tespit etmeniz gerekir :

Normalde, seçilen satırlar bulunursa çıkış durumu 0, aksi takdirde 1 olur. Ancak, -qveya --quietveya --silentseçeneği kullanılmazsa ve seçilen bir satır bulunmazsa , bir hata oluşursa çıkış durumu 2'dir . Bununla birlikte, bu gibi programlar için POSIX sadece görev, grep, cmp, ve diff, hata durumunda çıkış durumu 1'den büyük olması; bu nedenle, taşınabilirlik uğruna, 2 ile sıkı eşitlik yerine bu genel durumu test eden mantık kullanılması tavsiye edilir.

Kaynağındaki normal çıktıyı bastırmak için grepadresine yönlendirebilirsiniz /dev/null. Standart hatanın yönlendirilmeden kaldığına dikkat edin, bu nedenle grepyazdırabilecek hata iletileri konsolda muhtemelen istediğiniz gibi sonuçlanacaktır.

Üç vakayı ele almak için bir caseifade kullanabiliriz :

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
Bu komutu bash betiğinden çalıştırırsam 0 veya 1'i bir değişkene nasıl yakalarım?
Toren

6
@Toren En son çıkış durumuna kullanılarak erişilebilir $?. ififadenin yanında grep komutunu da kullanabilirsiniz (güncellenmiş yanıtta gösterildiği gibi).
Shawn Chin

5
Sen kullanabilirsiniz grep -Fqx "$FILENAME"ve değişken içeriği regex karakterler hakkında endişe gerekmez ve arama dizede bunları kullanmak zorunda olmayacaktır.
sonraki duyuruya kadar duraklatıldı.

4
Bu cevaba bakan insanlar için birkaç not: 1) Bash'da, 0 her zaman doğrudur ve her şey yanlıştır 2) -x bayrağını sadece tüm çizginin tam olarak eşleşmesini istiyorsanız kullanın. Dizenizin dosyada hiç bulunup bulunmadığını bulmak istiyorsanız, bunu kapalı bırakın. Dizenizin tam olarak var olup olmadığını, ancak tüm bir satırı zorunlu olarak (yani, tam bir kelime olarak) eşleştirmeden bulmak istiyorsanız, -w kullanın.
Schmick

1
Ben gethe yok -q / --silentgerekli mi? Bir hata oluşsa bile yanlış bir şekilde bash için "hepsi iyi" diyor. Eğer bunu doğru anladıysam. Bu dava için kusurlu bir kavram gibi görünüyor.
redanimalwar

90

Aşağıdaki çözümle ilgili olarak:

grep -Fxq "$FILENAME" my_list.txt

Merak ediyorsanız (yaptığım gibi) -Fxqdüz İngilizce'de ne anlama gelir:

  • F: PATTERN'in nasıl yorumlandığını etkiler (normal ifade yerine sabit dize)
  • x: Tüm çizgiyi eşleştir
  • q: Şşşt ... minimum baskı

Man dosyasından:

-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 dosya işlemeyi etkilemez, PATTERN'in nasıl yorumlandığını etkiler. Tipik olarak, PATTERN bir normal ifade olarak yorumlanır, ancak -F ile sabit bir dize olarak yorumlanır.
Adam S

41

Aklımdaki üç yöntem:

1) Yoldaki bir isim için kısa test (Durumunuzun bu olduğundan emin değilim)

ls -a "path" | grep "name"


2) Bir dosyadaki dize için kısa test

grep -R "string" "filepath"


3) Normal ifade kullanan daha uzun bash betiği:

#!/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

Herhangi bir döngüdeki normal ifadeyi değiştirmek için bir döngü kullanarak bir dosya içeriğinde birden çok dizeyi test etmeniz gerekiyorsa bu daha hızlı olmalıdır .


10
$ File_contenet'ten önce ve sonra boşluklar neden gerekli?
EminezArtus

Hızlı çözüm ve daha genelleştirilebilir bir çözüm için Artı 1
Wassadamo

19

Daha basit bir yol:

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

İpucu: /dev/nullKomutun çıkış durumunu istiyor, ancak çıktılar istemiyorsanız gönder .


1
veya :) -qile aynı olanı kullanın--quiet
rogerdpack

-qburada da en iyi cevap konusunda hemfikir ve dördüncü sırada bu dünyada adalet yok.
tatsu

14

En kolay ve basit yol:

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 dizginin dosyada kaç kez meydana geldiğini döndürür.


5

Sorunuzu doğru anladıysam, ihtiyacınız olanı yapmalısınız.

  1. $ check değişkeni ile eklemek istediğiniz dizini belirtebilirsiniz
  2. dizin zaten listede varsa, çıktı "dir zaten listelenir"
  3. dizin henüz listede yoksa, my_list.txt dosyasına eklenir

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


Grep'in çıktısını test etmenize gerek yok, sadece grep -qgrep'i doğrudan ifThomas'ın cevabında yaptığı gibi kullanabilir ve çağırabilirsiniz . Buna ek olarak, soru, dizinin listeye eklenmeden önce var olup olmadığını kontrol etmeyi içermiyordu (sonuçta silinmiş dizinlerin bir listesi olabilir).
sorpigal

Örnek senaryoyu kaldırdım, Thomas'ın verdiği cevaba hiçbir şey eklemedi.
lecodesportif

3

Sadece bir satırın varlığını kontrol etmek istiyorsanız, bir dosya oluşturmanız gerekmez. Örneğin,

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

Fgrep kullanan sürümüm

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

-cSeçeneği göremiyorumfgrep --help
Nam G VU

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

-E seçeneği grep'in düzenli ifadeler kullanmasını sağlar


1

@ Thomas'ın çözümü bir nedenden dolayı benim için işe yaramadı, ancak özel karakterler ve boşluklarla daha uzun bir dize vardı, bu yüzden sadece bu gibi parametreleri değiştirdim:

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

Umarım birine yardımcı olur



0
grep -Fxq "String to be found" | ls -a
  • grep will içeriği kontrol etmene yardımcı olur
  • ls tüm dosyaları listeler

@ThomWiggers Aynı şeyi denedim ve benim için çalıştı.
Shinoy Shaji

-1
if grep -q "$Filename$" my_list.txt
   then
     echo "exist"
else 
     echo "not exist"
fi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.