วิธีทดสอบว่ามีสตริงอยู่ในไฟล์ด้วย Bash


337

ฉันมีไฟล์ที่มีชื่อไดเรกทอรี:

my_list.txt :

/tmp
/var/tmp

ฉันต้องการตรวจสอบใน Bash ก่อนที่ฉันจะเพิ่มชื่อไดเรกทอรีหากชื่อนั้นมีอยู่แล้วในไฟล์


ในการค้นหาสตริงทั้งหมดในไฟล์คุณสามารถเรียกใช้ grep ใน FOR loop: unix.stackexchange.com/a/462445/43233
Noam Manos

คำตอบ:


655
grep -Fxq "$FILENAME" my_list.txt

สถานะการออกคือ 0 (จริง) หากพบชื่อ, 1 (เท็จ) หากไม่ใช่ดังนั้น:

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

คำอธิบาย

นี่คือส่วนที่เกี่ยวข้องของman page สำหรับgrep :

grep [options] PATTERN [FILE...]

-F, --fixed-strings

        ตีความรูปแบบเป็นรายการของสตริงคงที่คั่นด้วยบรรทัดใหม่ใด ๆ ที่จะต้องจับคู่

-x, --line-regexp

        เลือกเฉพาะการแข่งขันที่ตรงกับทั้งเส้น

-q, --quiet,--silent

        เงียบ; ห้ามเขียนอะไรไปยังเอาต์พุตมาตรฐาน ออกทันทีโดยมีสถานะเป็นศูนย์หากพบคู่ที่ตรงกันแม้ว่าตรวจพบข้อผิดพลาด ดูตัวเลือก-sหรือ--no-messages

การจัดการข้อผิดพลาด

ตามที่ระบุไว้อย่างถูกต้องในความคิดเห็นวิธีการดังกล่าวข้างต้นเงียบปฏิบัติกรณีข้อผิดพลาดราวกับว่าพบสตริง หากคุณต้องการจัดการข้อผิดพลาดในวิธีอื่นคุณจะต้องไม่ใช้-qตัวเลือกและตรวจหาข้อผิดพลาดตามสถานะการออก:

โดยปกติสถานะการออกคือ 0 หากพบบรรทัดที่เลือกและ 1 เป็นอย่างอื่น แต่สถานะการออกคือ 2 หากเกิดข้อผิดพลาดยกเว้นว่าจะใช้-qหรือ--quietหรือ--silentตัวเลือกและพบบรรทัดที่เลือก แต่โปรดทราบว่า POSIX เอกสารเท่านั้นสำหรับโปรแกรมเช่นgrep, cmpและdiffที่ออกจากสถานะในกรณีของข้อผิดพลาดจะสูงกว่า 1; ดังนั้นจึงแนะนำให้เลือกใช้ตรรกะที่ทดสอบเงื่อนไขทั่วไปนี้แทนความเสมอภาคที่เข้มงวดด้วย 2

เพื่อให้การปราบปรามการส่งออกตามปกติจากการที่คุณสามารถเปลี่ยนเส้นทางไปยังgrep /dev/nullโปรดทราบว่าข้อผิดพลาดมาตรฐานยังคงไม่ถูกนำไปใช้ดังนั้นข้อความแสดงข้อผิดพลาดใด ๆ ที่grepอาจพิมพ์จะจบลงที่คอนโซลตามที่คุณอาจต้องการ

ในการจัดการทั้งสามกรณีเราสามารถใช้caseคำสั่ง:

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
หากฉันรันคำสั่งนี้จากสคริปต์ทุบตีวิธีการจับ 0 หรือ 1 เป็นตัวแปร?
Toren

6
@Toren $?ออกจากสถานะล่าสุดส่วนใหญ่สามารถเข้าถึงได้โดยใช้ คุณยังสามารถใช้คำสั่ง grep ข้างifคำสั่ง (ดังที่แสดงในคำตอบที่ปรับปรุงแล้ว)
Shawn Chin

5
คุณสามารถใช้grep -Fqx "$FILENAME"และคุณไม่ต้องกังวลกับอักขระ regex ในเนื้อหาตัวแปรและคุณไม่ต้องใช้อักขระในสตริงการค้นหา
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

4
หมายเหตุสองสามข้อสำหรับผู้ใช้ที่ดูคำตอบนี้: 1) ใน bash, 0 เป็นจริงเสมอและสิ่งอื่นใดเป็นเท็จเสมอ 2) ใช้แฟล็ก -x หากคุณต้องการให้ทั้งบรรทัดตรงกันเท่านั้น หากคุณแค่ต้องการค้นหาว่าสตริงของคุณมีอยู่ในไฟล์หรือไม่ให้ปล่อยทิ้งไว้ หากคุณต้องการค้นหาว่าสตริงของคุณมีอยู่จริงหรือไม่โดยไม่ต้องจับคู่ทั้งบรรทัดจำเป็นต้องใช้
Schmick

1
ฉันไม่เข้าใจ-q / --silentมันจำเป็นหรือไม่ มันเท็จว่า "ดีทั้งหมด" เพื่อทุบตีแม้ว่าจะมีข้อผิดพลาดเกิดขึ้น ถ้าฉันได้รับอย่างถูกต้อง ดูเหมือนว่าแนวคิดที่มีข้อบกพร่องสำหรับกรณีนี้
redanimalwar

90

เกี่ยวกับการแก้ปัญหาต่อไปนี้:

grep -Fxq "$FILENAME" my_list.txt

ในกรณีที่คุณสงสัย (เหมือนที่ฉันทำ) สิ่งที่-Fxqเป็นภาษาอังกฤษธรรมดา:

  • F: มีผลต่อวิธีการตีความแบบ (สตริงคงที่แทนที่จะเป็น regex)
  • x: จับคู่ทั้งบรรทัด
  • q: Shhhhh ... การพิมพ์ขั้นต่ำ

จากไฟล์ 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 ไม่ส่งผลกระทบต่อการประมวลผลไฟล์มันมีผลต่อวิธีการตีความแบบ โดยทั่วไปรูปแบบถูกตีความว่าเป็น regex แต่ด้วย -F มันจะถูกตีความว่าเป็นสตริงคงที่
Adam S

41

สามวิธีในใจของฉัน:

1) การทดสอบสั้น ๆ สำหรับชื่อในพา ธ (ฉันไม่แน่ใจว่านี่อาจเป็นกรณีของคุณ)

ls -a "path" | grep "name"


2) การทดสอบสั้น ๆ สำหรับสตริงในไฟล์

grep -R "string" "filepath"


3) สคริปต์ทุบตีอีกต่อไปโดยใช้ 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

สิ่งนี้น่าจะเร็วกว่าถ้าคุณต้องทดสอบหลาย ๆ สตริงในเนื้อหาไฟล์โดยใช้การวนซ้ำตัวอย่างเช่นการเปลี่ยน regex ที่ cicle ใด ๆ


10
เหตุใดช่องว่างจึงจำเป็นก่อนและหลัง $ file_contenet
EminezArtus

บวก 1 สำหรับการแก้ปัญหาที่รวดเร็วและการปรับเปลี่ยนได้มากกว่า
Wassadamo

19

วิธีที่ง่ายกว่า:

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

เคล็ดลับ: ส่งไปยัง/dev/nullหากคุณต้องการสถานะการออกของคำสั่ง แต่จะไม่ส่งออก


1
หรือใช้-qซึ่งเหมือนกับ--quiet:)
rogerdpack

เห็นด้วยกับ-qคำตอบที่ดีที่สุดที่นี่และเป็นที่สี่ ไม่มีความยุติธรรมในโลกนี้
tatsu

14

วิธีที่ง่ายที่สุดและง่ายที่สุดคือ:

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 จะคืนค่าจำนวนสตริงที่เกิดขึ้นในไฟล์


5

หากฉันเข้าใจคำถามของคุณถูกต้องสิ่งนี้ควรทำในสิ่งที่คุณต้องการ

  1. คุณสามารถระบุไดเรกทอรีที่คุณต้องการเพิ่มผ่านตัวแปร $ check
  2. หากไดเรกทอรีอยู่ในรายการแล้วผลลัพธ์จะเป็น "dir อยู่แล้ว"
  3. หากไดเรกทอรียังไม่อยู่ในรายการไดเรกทอรีนั้นจะถูกผนวกเข้ากับ my_list.txt

ในหนึ่งบรรทัด :check="/tmp/newdirectory"; [[ -n $(grep "^$check\$" my_list.txt) ]] && echo "dir already listed" || echo "$check" >> my_list.txt


คุณไม่จำเป็นต้องทดสอบผลลัพธ์ของ grep คุณสามารถใช้ grep -qและเรียก grep โดยตรงจากifที่ Thomas ทำในคำตอบของเขา นอกจากนี้คำถามไม่ได้รวมการตรวจสอบว่ามีไดเรกทอรีอยู่ก่อนที่จะเพิ่มลงในรายการหรือไม่ (อาจเป็นรายการของไดเรกทอรีที่ถูกลบหลังจากทั้งหมด)
sorpigal

ฉันลบสคริปต์ตัวอย่างออกแล้วมันไม่ได้เพิ่มอะไรเลยกับคำตอบที่โทมัสมอบให้
lecodesportif

3

หากคุณต้องการตรวจสอบการมีอยู่ของหนึ่งบรรทัดคุณไม่จำเป็นต้องสร้างไฟล์ เช่น,

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

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

ฉันไม่เห็น-cตัวเลือกในfgrep --help
Nam G VU


1

วิธีแก้ปัญหาของ @ Thomas ไม่ได้ผลสำหรับฉันด้วยเหตุผลบางอย่าง แต่ฉันมีสตริงที่ยาวกว่าด้วยอักขระพิเศษและช่องว่างดังนั้นฉันจึงเปลี่ยนพารามิเตอร์ดังนี้:

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

หวังว่าจะช่วยใครซักคน


0

วิธีแก้ปัญหา grep-less เหมาะกับฉัน:

MY_LIST=$( cat /path/to/my_list.txt )



if [[ "${MY_LIST}" == *"${NEW_DIRECTORY_NAME}"* ]]; then
  echo "It's there!"
else
echo "its not there"
fi

อิงตาม: https://stackoverflow.com/a/229606/3306354


1
ใช้หน่วยความจำมากเกินไปในกรณีที่ไฟล์มีขนาดใหญ่ grep -qอธิบายไว้ในคำตอบที่ยอมรับได้เป็นวิธีที่มีประสิทธิภาพที่สุด
codeforester

0
grep -Fxq "String to be found" | ls -a
  • grep จะช่วยคุณตรวจสอบเนื้อหา
  • ls จะแสดงรายการไฟล์ทั้งหมด

@ThomWiggers ฉันลองแบบเดียวกันและมันก็ใช้ได้กับฉัน
Shinoy Shaji

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.