ทดสอบว่ากลมมีการแข่งขันใด ๆ ในทุบตี


223

ถ้าผมต้องการที่จะตรวจสอบการดำรงอยู่ของไฟล์เดียวที่ฉันสามารถทดสอบได้โดยใช้หรือtest -e filename[ -e filename ]

สมมติว่าฉันมี glob และฉันต้องการที่จะรู้ว่ามีไฟล์ใด ๆ ที่มีชื่อตรงกับ glob glob สามารถจับคู่ไฟล์ 0 (ในกรณีที่ฉันไม่ต้องทำอะไร) หรือสามารถจับคู่ไฟล์ 1 ไฟล์หรือมากกว่า (ซึ่งในกรณีนี้ฉันต้องทำบางสิ่ง) ฉันจะทดสอบว่า glob มีคู่ที่ตรงกันได้อย่างไร (ฉันไม่สนใจว่ามีการแข่งขันกี่รายการและมันจะดีที่สุดถ้าฉันสามารถทำสิ่งนี้ด้วยifคำสั่งเดียวและไม่มีการวนซ้ำ(เพียงเพราะฉันพบว่าการอ่านที่มากที่สุด)

( test -e glob*ล้มเหลวหาก glob ตรงกับมากกว่าหนึ่งไฟล์)


3
ฉันสงสัยว่าคำตอบของฉันด้านล่างนี้ 'ถูกต้องชัดเจน' ในลักษณะที่การแฮ็กข้อมูลอื่น ๆ มันเป็นเชลล์ - บิวด์อินเส้นเดียวที่อยู่รอบตัวตลอดไปและดูเหมือนจะเป็น 'เครื่องมือที่มีไว้สำหรับงานนี้โดยเฉพาะ' ฉันกังวลว่าผู้ใช้จะอ้างอิงคำตอบที่ยอมรับโดยไม่ตั้งใจที่นี่ ใครก็ตามโปรดแก้ไขฉันและฉันจะถอนความคิดเห็นของฉันที่นี่ฉันมีความสุขมากกว่าที่จะผิดและเรียนรู้จากมัน หากความแตกต่างนั้นไม่รุนแรงนักฉันจะไม่ยกประเด็นนี้ขึ้น
Brian Chrisman

1
คำตอบที่ฉันโปรดปรานสำหรับคำถามนี้คือคำสั่ง findที่ทำงานในเชลล์ใด ๆ (แม้แต่เชลล์ที่ไม่ใช่บอร์น) แต่ต้องใช้ GNU find และคำสั่ง compgenซึ่งเห็นได้ชัดว่าเป็นการทุบตี น่าเสียดายที่ฉันไม่สามารถยอมรับคำตอบทั้งคู่ได้
Ken Bloom

หมายเหตุ: คำถามนี้ได้รับการแก้ไขตั้งแต่มีการถาม ชื่อเดิมคือ "ทดสอบว่ากลมมีการแข่งขันใด ๆ ในทุบตี" เชลล์เฉพาะ 'bash' ถูกลบออกจากคำถามหลังจากที่ฉันเผยแพร่คำตอบของฉัน การแก้ไขชื่อคำถามทำให้คำตอบของฉันดูเหมือนว่าผิดพลาด ฉันหวังว่าบางคนสามารถแก้ไขได้หรืออย่างน้อยก็จัดการกับการเปลี่ยนแปลงนี้
Brian Chrisman

คำตอบ:


178

วิธีการแก้ปัญหาเฉพาะทุบตี :

compgen -G "<glob-pattern>"

หลีกเลี่ยงรูปแบบหรือมันจะถูกขยายก่อนการแข่งขัน

สถานะการออกคือ:

  • 1 สำหรับไม่ตรงกัน
  • 0 สำหรับ 'การแข่งขันอย่างน้อยหนึ่งรายการ'

stdoutเป็นรายการของไฟล์ที่ตรงกับ glob
ฉันคิดว่านี่เป็นตัวเลือกที่ดีที่สุดในแง่ของความกระชับและลดผลข้างเคียงที่อาจเกิดขึ้น

UPDATE : ตัวอย่างการใช้งานที่ร้องขอ

if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi

9
โปรดทราบว่าcompgenเป็นคำสั่งในตัวbash -specific และไม่ได้เป็นส่วนหนึ่งของ POSIX มาตรฐาน Unix shell ที่ระบุคำสั่งในตัว pubs.opengroup.org/onlinepubs/9699919799 pubs.opengroup.org/onlinepubs/9699919799/utilities/…ดังนั้นหลีกเลี่ยงการใช้งานในสคริปต์ที่ความสะดวกในการพกพาเชลล์อื่น ๆ เป็นเรื่องที่น่ากังวล
Diomidis Spinellis

1
ดูเหมือนว่าสำหรับฉันแล้วเอฟเฟกต์ที่คล้ายกันโดยไม่ต้องใช้ bash builtins ก็คือการใช้คำสั่งอื่นที่ทำงานบน glob และล้มเหลวหากไม่มีไฟล์ที่ตรงเช่น ls: if ls /tmp/*Files 2>&1 >/dev/null; then echo exists; fi- อาจมีประโยชน์สำหรับ code golf หรือไม่ ล้มเหลวหากมีไฟล์ชื่อเช่นเดียวกับ glob ซึ่ง glob ไม่ควรจับคู่ แต่ถ้าเป็นกรณีนี้คุณอาจมีปัญหาที่ใหญ่กว่า
Dewi Morgan

4
@DewiMorgan สิ่งนี้ง่ายกว่า:if ls /tmp/*Files &> /dev/null; then echo exists; fi
Clay Bridges

สำหรับรายละเอียดเกี่ยวกับcompgenโปรดดูman bashหรือกับhelp compgen
el-teedee

2
ใช่อ้างว่าหรือชื่อไฟล์จะถูกขยายก่อน compgen "dir / *. ext"
Brian Chrisman

169

ตัวเลือก nullglob shell เป็น bashism แน่นอน

เพื่อหลีกเลี่ยงความจำเป็นในการบันทึกและกู้คืนสถานะ nullglob ที่น่าเบื่อฉันต้องตั้งค่าภายใน subshell ที่ขยาย glob:

if test -n "$(shopt -s nullglob; echo glob*)"
then
    echo found
else
    echo not found
fi

เพื่อความสะดวกในการพกพาที่ดีขึ้นและมีความยืดหยุ่นมากขึ้นให้ใช้ find:

if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
    echo found
else
    echo not found
fi

การดำเนินการอย่างชัดเจน-print -quitจะใช้สำหรับการค้นหาแทนการดำเนินการ-printโดยปริยายเริ่มต้นเพื่อให้การค้นหาจะออกจากทันทีที่พบไฟล์แรกที่ตรงกับเกณฑ์การค้นหา ตรงกับที่ไฟล์จำนวนมากมันควรจะทำงานได้เร็วกว่าecho glob*หรือls glob*จะหลีกเลี่ยงความเป็นไปได้ของการใช้งานเกินบรรทัดคำสั่งที่ขยาย (เชลล์บางตัวมีขีดจำกัดความยาว 4K)

หากพบว่ารู้สึกว่าเกินขนาดและจำนวนไฟล์ที่น่าจะมีขนาดเล็กให้ใช้ stat:

if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi

10
findดูเหมือนว่าจะถูกต้องอย่างแน่นอน ไม่มีกรณีมุมเนื่องจากเชลล์ไม่ได้ทำการขยาย (และส่ง glob ที่ไม่ได้ขยายไปยังคำสั่งอื่น) มันเป็นแบบพกพาระหว่างเชลล์ (แม้ว่าจะไม่ได้ระบุตัวเลือกทั้งหมดที่คุณใช้โดย POSIX) และเร็วกว่าls -d glob*(คำตอบที่ยอมรับก่อนหน้านี้) เพราะมันหยุดเมื่อถึงการแข่งขันครั้งแรก
Ken Bloom

1
โปรดทราบว่าคำตอบนี้อาจจำเป็นต้องมีshopt -u failglobตัวเลือกเหล่านี้ดูเหมือนจะขัดแย้งกันอย่างใด
Calimo

findวิธีการแก้ปัญหาจะตรงกับชื่อไฟล์ที่ไม่มีตัวละครแบบกลมเช่นกัน ในกรณีนี้นั่นคือสิ่งที่ฉันต้องการ สิ่งที่ต้องระวัง
พวกเราทุกคนโมนิก้า

1
เนื่องจากมีคนอื่นตัดสินใจแก้ไขคำตอบของฉันเพื่อให้พูดอย่างนั้น
flabdablet

1
unix.stackexchange.com/questions/275637/…อธิบายถึงวิธีการแทนที่-maxdepthตัวเลือกสำหรับ POSIX find
Ken Bloom

25
#!/usr/bin/env bash

# If it is set, then an unmatched glob is swept away entirely -- 
# replaced with a set of zero words -- 
# instead of remaining in place as a single word.
shopt -s nullglob

M=(*px)

if [ "${#M[*]}" -ge 1 ]; then
    echo "${#M[*]} matches."
else
    echo "No such files."
fi

2
เพื่อหลีกเลี่ยงการตั้งค่า“ ไม่มีการจับคู่” ที่ผิดพลาดnullglobแทนการตรวจสอบเพื่อดูว่าผลลัพธ์เดียวเท่ากับรูปแบบนั้นหรือไม่ บางรูปแบบสามารถจับคู่ชื่อที่ตรงกับรูปแบบของตัวเอง (เช่นa*b; แต่ไม่ใช่เช่นa?bหรือ[a])
Chris Johnsen

ฉันคิดว่าสิ่งนี้ล้มเหลวในโอกาสที่ไม่น่าเป็นไปได้สูงที่จริง ๆ แล้วมีไฟล์ชื่อเช่น glob (เช่นมีคนวิ่งtouch '*py') แต่สิ่งนี้ชี้ให้ฉันไปในทิศทางที่ดีอีกทางหนึ่ง
Ken Bloom

ฉันชอบอันนี้เป็นรุ่นทั่วไปที่สุด
Ken Bloom

และยังสั้นที่สุด หากคุณเป็นเพียงการคาดหวังว่าการแข่งขันหนึ่งคุณสามารถใช้เป็นชวเลขเป็น"$M" "${M[0]}"มิฉะนั้นคุณมีการขยาย glob ในตัวแปรอาร์เรย์ดังนั้นคุณ gtg สำหรับส่งผ่านไปยังสิ่งอื่น ๆ ในรายการแทนที่จะทำให้พวกมันขยาย glob อีกครั้ง
Peter Cordes

ดี คุณสามารถทดสอบ M ได้รวดเร็วยิ่งขึ้น (น้อยกว่าไบต์และไม่มีการวางไข่ใน[กระบวนการ) ด้วยif [[ $M ]]; then ...
Tobia

22

ฉันชอบ

exists() {
    [ -e "$1" ]
}

if exists glob*; then
    echo found
else
    echo not found
fi

นี่เป็นทั้งการอ่านและมีประสิทธิภาพ (เว้นแต่จะมีไฟล์จำนวนมาก)
ข้อเสียเปรียบหลักคือมันบอบบางกว่าที่ดูมากและบางครั้งฉันรู้สึกว่าถูกบังคับให้เพิ่มความคิดเห็นยาว ๆ
หากมีการแข่งขัน"glob*"จะถูกขยายโดยเชลล์และการแข่งขันทั้งหมดจะถูกส่งผ่านไปexists()ซึ่งจะตรวจสอบครั้งแรกและละเว้นส่วนที่เหลือ
หากไม่มีการแข่งขัน"glob*"จะถูกส่งไปที่exists()และไม่พบว่ามีอยู่จริง

แก้ไข: อาจมีการบวกปลอมดูความคิดเห็น


13
มันอาจกลับมาเป็นบวกเท็จถ้า glob เป็นสิ่งที่ต้องการ*.[cC](อาจจะไม่มีcหรือCไฟล์ แต่ไฟล์ที่เรียกว่า*.[cC]) หรือเท็จลบหากไฟล์แรกที่ขยายจากนั้นเป็นเช่น symlink ไปยังไฟล์ที่ไม่อยู่หรือไฟล์ใน ไดเรกทอรีที่คุณไม่มีสิทธิ์เข้าถึง (คุณต้องการเพิ่ม|| [ -L "$1" ])
Stephane Chazelas

น่าสนใจ Shellcheck รายงานว่าการวนซ้ำทำงานได้เฉพาะ-eเมื่อมีการจับคู่ 0 หรือ 1 มันไม่ทำงานสำหรับการแข่งขันหลายนัดเพราะมันจะกลายเป็น[ -e file1 file2 ]และสิ่งนี้จะล้มเหลว ดูgithub.com/koalaman/shellcheck/wiki/SC2144สำหรับเหตุผลและวิธีแก้ปัญหาที่แนะนำ
Thomas Praxl

10

หากคุณมีชุด globfail คุณสามารถใช้มันบ้า (ซึ่งคุณไม่ควร)

shopt -s failglob # exit if * does not match 
( : * ) && echo 0 || echo 1

หรือ

q=( * ) && echo 0 || echo 1

2
การใช้งานที่ยอดเยี่ยมของ noop ที่ล้มเหลว ไม่ควรใช้ ... แต่สวยงามจริงๆ :)
Brian Chrisman

คุณสามารถวาง shopt ภายใน parens วิธีนี้จะส่งผลต่อการทดสอบเท่านั้น:(shopt -s failglob; : *) 2>/dev/null && echo exists
flabdablet

8

ทดสอบ -e มีข้อแม้ที่โชคร้ายที่จะพิจารณาการเชื่อมโยงสัญลักษณ์ที่ใช้งานไม่ได้ ดังนั้นคุณอาจต้องการตรวจสอบสิ่งเหล่านั้นด้วย

function globexists {
  test -e "$1" -o -L "$1"
}

if globexists glob*; then
    echo found
else
    echo not found
fi

4
แต่นั่นก็ไม่ได้แก้ไขชื่อไฟล์ที่มีตัวละครพิเศษในตัวพวกมันผิด ๆ อย่างเช่นสเตฟานชาเซล่าชี้ให้เห็นถึงคำตอบของแดนบลอค (เว้นแต่คุณจะลิงด้วย nullglob)
Peter Cordes

3
คุณ shoud หลีกเลี่ยง-oและ-aใน/test [ยกตัวอย่างเช่นนี่มันล้มเหลวถ้า$1เป็น=กับการใช้งานมากที่สุด ใช้[ -e "$1" ] || [ -L "$1" ]แทน
Stephane Chazelas

4

เพื่อทำให้คำตอบของ MYYN ง่ายขึ้นบ้างตามความคิดของเขา:

M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
fi

4
ปิด แต่ถ้าคุณจับคู่[a]มีไฟล์ชื่อ[a]แต่ไม่มีชื่อไฟล์a? ฉันยังคงชอบnullglobสิ่งนี้ บางคนอาจมองว่านี่เป็นเรื่องหยาบคาย แต่เราอาจแก้ไขให้ถูกต้องตามที่ควร
Chris Johnsen

@ sondra.kinsey นั่นมันผิด glob [a]เท่านั้นควรจะตรงกับที่ไม่ได้ชื่อไฟล์ตัวอักษรa [a]
tripleee

4

ตามคำตอบของ flabdabletสำหรับฉันมันดูเหมือนง่ายที่สุด (ไม่จำเป็นต้องเร็วที่สุด) เพียงเพื่อใช้ค้นหาตัวเองในขณะที่ปล่อยให้การขยายตัวของ glob บนเปลือกเช่น:

find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH"

หรือifชอบ:

if find $yourGlob -quit &> /dev/null; then
    echo "MATCH"
else
    echo "NOT-FOUND"
fi

สิ่งนี้ทำงานได้เหมือนกับเวอร์ชั่นที่ฉันได้แสดงโดยใช้สถิติ ไม่แน่ใจว่าการค้นหานั้นง่ายกว่าสถิติ
flabdablet

3
โปรดทราบว่าการเปลี่ยนเส้นทาง &> นั้นเป็นการทุบตีและจะทำสิ่งผิดปกติในเชลล์อื่น ๆ อย่างเงียบ ๆ
flabdablet

ดูเหมือนว่าจะดีกว่าfindคำตอบของ flabdablet เพราะยอมรับเส้นทางใน glob และมันสั้นกว่า (ไม่ต้องการ-maxdepthฯลฯ ) นอกจากนี้ยังดูเหมือนว่าจะดีกว่าstatคำตอบของเขาเพราะมันไม่ได้statเพิ่มการแข่งขันเพิ่มเติมในการแข่งขันแต่ละรอบเพิ่มเติม ฉันขอขอบคุณถ้าใครสามารถมีส่วนร่วมกรณีมุมที่ไม่ได้
drwatsoncode

1
หลังจากพิจารณาเพิ่มเติมฉันจะเพิ่ม-maxdepth 0เพราะมันช่วยเพิ่มความยืดหยุ่นในการเพิ่มเงื่อนไข เช่นสมมติว่าฉันต้องการ จำกัด ผลลัพธ์เฉพาะไฟล์ที่ตรงกันเท่านั้น ฉันอาจลองใช้find $glob -type f -quitแต่นั่นจะกลับมาจริงถ้า glob ไม่ตรงกับไฟล์ แต่จับคู่ไดเรกทอรีที่มีไฟล์อยู่ (แม้จะเรียกซ้ำ) ในทางตรงกันข้ามfind $glob -maxdepth 0 -type f -quitจะกลับมาจริงถ้าตัวกลมที่ตรงกับอย่างน้อยหนึ่งไฟล์ โปรดทราบmaxdepthว่าไม่ได้ป้องกัน glob จากการมีองค์ประกอบไดเรกทอรี (FYI 2>ก็เพียงพอแล้วไม่จำเป็นต้องใช้&>)
drwatsoncode

2
จุดใช้งานfindในตอนแรกคือการหลีกเลี่ยงการสร้างเชลล์และเรียงลำดับรายการการแข่งขันแบบกลมที่อาจเกิดขึ้นได้ find -name ... -quitจะจับคู่กับชื่อไฟล์ได้มากที่สุดหนึ่งรายการ หากสคริปต์อาศัยการส่งผ่านรายการ glob ที่สร้างโดยเชลล์การfindเรียกใช้findจะไม่ประสบความสำเร็จนอกจากค่าใช้จ่ายในการเริ่มต้นกระบวนการที่ไม่จำเป็น เพียงทดสอบรายการผลลัพธ์โดยตรงสำหรับความว่างเปล่าจะรวดเร็วและชัดเจนขึ้น
flabdablet

4

ฉันมีวิธีแก้ไขปัญหาอื่น:

if [ "$(echo glob*)" != 'glob*' ]

มันใช้งานได้ดีสำหรับฉัน มีบางกรณีที่ฉันพลาดหรือไม่?


2
ใช้งานได้ยกเว้นว่าไฟล์นั้นมีชื่อว่า 'glob *'
Ian Kelling

ทำงานเพื่อส่งผ่าน glob เป็นตัวแปร - ให้ข้อผิดพลาด "มีอาร์กิวเมนต์มากเกินไป" เมื่อมีการแข่งขันมากกว่าหนึ่งรายการ "$ (echo $ GLOB)" จะไม่ส่งคืนสตริงเดี่ยวหรืออย่างน้อยก็ไม่ได้ตีความว่าเป็นสตริงเดี่ยวดังนั้นข้อผิดพลาดการขัดแย้งมากเกินไป
DKebler

@DKebler: มันควรจะตีความว่าเป็นสตริงเดียวเพราะมันถูกห่อด้วยเครื่องหมายคำพูดคู่
user1934428

3

ใน Bash คุณสามารถ glob ไปยังอาร์เรย์ได้ หาก glob ไม่ตรงกับอาร์เรย์ของคุณจะมีรายการเดียวที่ไม่ตรงกับไฟล์ที่มีอยู่:

#!/bin/bash

shellglob='*.sh'

scripts=($shellglob)

if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi

หมายเหตุ: หากคุณnullglobตั้งค่าไว้scriptsจะเป็นอาร์เรย์ว่างเปล่าและคุณควรทดสอบด้วย[ "${scripts[*]}" ]หรือ[ "${#scripts[*]}" != 0 ]แทน หากคุณกำลังเขียนไลบรารีที่ต้องใช้งานหรือไม่ใช้nullglobคุณจะต้อง

if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]

ข้อดีของวิธีนี้คือคุณมีรายการไฟล์ที่คุณต้องการใช้งานแทนที่จะต้องทำซ้ำการทำงานแบบ glob


ทำไมถึงตั้งค่า nullglob และอาร์เรย์อาจว่างเปล่าคุณยังไม่สามารถทดสอบด้วยได้ if [ -e "${scripts[0]}" ]...หรือไม่ คุณยังอนุญาตความเป็นไปได้ของคำนามชุดตัวเลือกเชลล์หรือไม่?
johnraff

@johnraff ใช่ฉันปกติถือว่าnounsetมีการใช้งาน นอกจากนี้อาจมีราคาถูกกว่า (เล็กน้อย) ในการทดสอบสตริงว่าไม่ว่างเปล่ากว่าการตรวจสอบว่ามีไฟล์อยู่หรือไม่ ไม่น่าเป็นไปได้ว่าเราเพิ่งทำแบบกลมหมายความว่าเนื้อหาไดเรกทอรีควรสดในแคชของระบบปฏิบัติการ
Toby Speight

1

สิ่งที่น่ารังเกียจนี้ดูเหมือนจะได้ผล:

#!/usr/bin/env bash
shopt -s nullglob
if [ "`echo *py`" != "" ]; then
    echo "Glob matched"
else
    echo "Glob did not match"
fi

อาจต้องใช้ bash ไม่ใช่ sh

สิ่งนี้ทำงานได้เพราะตัวเลือก nullglob ทำให้ glob ทำการประเมินสตริงที่ว่างเปล่าหากไม่มีการจับคู่ ดังนั้นเอาต์พุตที่ไม่ว่างเปล่าจากคำสั่ง echo บ่งชี้ว่า glob ตรงกับบางอย่าง


คุณควรใช้if [ "`echo *py`" != "*py"]
yegle

1
*pyที่จะไม่ทำงานอย่างถูกต้องถ้ามีไฟล์ที่เรียกว่า
Ryan C. Thompson

ถ้าไม่มีที่สิ้นสุดไฟล์ที่มีpy, จะได้รับการประเมิน`echo *py` *py
yegle

1
ใช่ แต่มันจะทำเช่นนั้นหากมีไฟล์เดียวที่เรียกว่า*pyซึ่งเป็นผลที่ผิด
Ryan C. Thompson

ถูกต้องฉันถ้าฉันผิด แต่ถ้าไม่มีไฟล์ที่ตรงกับ*pyสคริปต์ของคุณจะสะท้อน "Glob ที่ตรงกัน"?
yegle


1
set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi

คำอธิบาย

เมื่อไม่มีการแข่งขันglob*แล้วจะมี$1 'glob*'การทดสอบ-f "$1"จะไม่เป็นจริงเพราะglob*ไม่มีไฟล์อยู่

ทำไมสิ่งนี้ถึงดีกว่าทางเลือกอื่น

ใช้งานได้กับ sh และอนุพันธ์: ksh และ bash มันไม่ได้สร้างเชลล์ย่อยใด ๆ $(..)และ`...`คำสั่งสร้างเชลล์ย่อย พวกเขาแยกกระบวนการและดังนั้นจึงช้ากว่าโซลูชันนี้


1

ถูกใจสิ่งนี้ใน (ทดสอบไฟล์ที่มีpattern):

shopt -s nullglob
compgen -W *pattern* &>/dev/null
case $? in
    0) echo "only one file match" ;;
    1) echo "more than one file match" ;;
    2) echo "no file match" ;;
esac

มันดีกว่าcompgen -G: เพราะเราสามารถแยกแยะกรณีและความแม่นยำได้มากขึ้น

สามารถทำงานกับสัญลักษณ์ตัวแทนได้เพียงอันเดียว *


0
if ls -d $glob > /dev/null 2>&1; then
  echo Found.
else
  echo Not found.
fi

โปรดทราบว่าการทำเช่นนี้อาจใช้เวลานานมากหากมีการจับคู่จำนวนมากหรือการเข้าถึงไฟล์ช้า


1
นี่จะให้คำตอบที่ไม่ถูกต้องหากใช้รูปแบบเช่น[a]นี้เมื่อมีไฟล์[a]อยู่และไฟล์aนั้นขาดหายไป มันจะพูดว่า "พบ" แม้ว่าไฟล์เดียวที่ควรจะตรงกัน แต่aไม่ได้มีอยู่จริง
Chris Johnsen

รุ่นนี้ควรทำงานใน POSIX / bin / sh ธรรมดา (โดยไม่ต้อง bashisms) และในกรณีที่ฉันต้องการสำหรับ glob ไม่ได้มีวงเล็บอยู่แล้วและฉันไม่ต้องกังวลเกี่ยวกับกรณีที่ พยาธิวิทยาชะมัด แต่ฉันเดาว่าไม่มีวิธีที่ดีที่จะทดสอบว่ามีไฟล์ใดที่ตรงกับ glob หรือไม่
Ken Bloom

0
#!/bin/bash
set nullglob
touch /tmp/foo1 /tmp/foo2 /tmp/foo3
FOUND=0
for FILE in /tmp/foo*
do
    FOUND=$((${FOUND} + 1))
done
if [ ${FOUND} -gt 0 ]; then
    echo "I found ${FOUND} matches"
else
    echo "No matches found"
fi

2
รุ่นนี้ล้มเหลวเมื่อตรงกับไฟล์เดียว แต่คุณสามารถหลีกเลี่ยง FOUND = -1 kludge โดยใช้nullglobตัวเลือกเชลล์
Ken Bloom

@ เคน: อืมฉันจะไม่เรียกnullglobkludge การเปรียบเทียบผลลัพธ์เดียวกับรูปแบบดั้งเดิมคือ kludge (และมีแนวโน้มที่จะได้ผลลัพธ์ที่ผิดพลาด) การใช้nullglobไม่ใช่
Chris Johnsen

@Chris: ฉันคิดว่าคุณเข้าใจผิด ฉันไม่ได้เรียกnullglobkludge
Ken Bloom

1
@Ken: แน่นอนฉันเข้าใจผิด โปรดยอมรับคำขอโทษของฉันสำหรับคำวิจารณ์ที่ไม่ถูกต้อง
Chris Johnsen

-1
(ls glob* &>/dev/null && echo Files found) || echo No file found

5
จะส่งกลับค่า false ถ้ามีไดเรกทอรีที่ตรงกันglob*และตัวอย่างเช่นคุณไม่มีการเขียนเพื่อแสดงรายการไดเรกทอรีเหล่านั้น
Stephane Chazelas

-1

ls | grep -q "glob.*"

ไม่ใช่วิธีที่มีประสิทธิภาพที่สุด (ถ้ามีไฟล์จำนวนมากในไดเรกทอรีมันอาจจะช้า) แต่มันง่ายอ่านง่ายและมีข้อดีที่ regexes มีประสิทธิภาพมากกว่ารูปแบบ bash glob ธรรมดา


-2
[ `ls glob* 2>/dev/null | head -n 1` ] && echo true

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