ฉันจะบอกได้อย่างไรว่าไฟล์ปกติไม่มีอยู่ใน Bash


3261

ฉันใช้สคริปต์ต่อไปนี้เพื่อดูว่ามีไฟล์อยู่หรือไม่:

#!/bin/bash

FILE=$1     
if [ -f $FILE ]; then
   echo "File $FILE exists."
else
   echo "File $FILE does not exist."
fi

อะไรไวยากรณ์ที่ถูกต้องที่จะใช้ถ้าฉันเพียงต้องการตรวจสอบว่าไฟล์ไม่ได้อยู่?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi


9
การเป็นคนขี้เกียจอย่างที่ฉันเป็นฉันมักจะใช้โครงสร้างการแก้ปัญหาโง่ ๆ ดังต่อไปนี้: if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi;น่าจะดีที่ฉันพบคำถามนี้แทนและเรียนรู้ที่จะทำมันด้วยวิธีที่เหมาะสมกว่า :)
Alderath

5
เพื่อให้เป็นจี้คุณควรพูดว่า "ไฟล์ปกติ" เนื่องจากเอกสาร UNIX / POSIX ส่วนใหญ่อ้างอิงโดยทั่วไปถึงรายการระบบไฟล์ทุกประเภทเป็น "ไฟล์" เพียงอย่างเดียวเช่นลิงก์สัญลักษณ์เป็นประเภทไฟล์เช่นเดียวกับไพพ์ที่มีชื่อ ไฟล์ปกติไดเรกทอรีบล็อกพิเศษอักขระพิเศษซ็อกเก็ต ฯลฯ
kevinarpe

11
@kevinarpe ถ้าคุณต้องการที่จะทดสอบว่าบางสิ่งบางอย่าง-eที่มีอยู่ใช้งาน -f จะไม่เก็บไดเรกทอรี, symlink, ฯลฯ
Benubird

14
เพื่อความปลอดภัยให้ใช้เครื่องหมายคำพูดคู่เสมอเพื่อจัดการชื่อไฟล์อย่างถูกต้องด้วยช่องว่างเช่นFILE=$1-> FILE="$1"และif [ -f $FILE ];->if [ -f "$FILE" ];
kevinarpe

คำตอบ:


4522

ทดสอบคำสั่ง ( [ที่นี่) มี "ไม่ได้" ผู้ประกอบการตรรกะซึ่งเป็นเครื่องหมายอัศเจรีย์ (คล้ายกับภาษาอื่น ๆ อีกมากมาย) ลองสิ่งนี้:

if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi

208
ชัดถ้อยชัดคำมากขึ้น: [! -f /tmp/foo.txt] && echo "ไม่พบไฟล์!"
DavidWinterbottom

38
ฉันพยายามหาไวยากรณ์ที่ถูกต้องสำหรับ "ถ้าไม่มีไฟล์ใด ๆ 2 ไฟล์" ทั้งสองทำงานดังต่อไปนี้:if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi
mivk

153
@DavidWinterbottom สำเร็จมากยิ่งขึ้น:[ -f /tmp/foo.txt ] || echo "File not found!"
David W.

27
พารามิเตอร์สามารถเป็นอย่างใดอย่างหนึ่งต่อไปนี้:-e: Returns true value, if file exists -f: Return true value, if file exists and regular file -r: Return true value, if file exists and is readable -w: Return true value, if file exists and is writable -x: Return true value, if file exists and is executable -d: Return true value, if exists and is a directory
SD

5
มีความไม่สมดุลในการใช้เป็น! -fด้วย&&เมื่อเทียบกับการใช้กับ-f ||สิ่งนี้เกี่ยวข้องกับรหัสทางออกที่ส่งคืนโดยการตรวจสอบที่ไม่มีอยู่ หากคุณต้องการให้บรรทัดของคุณออกอย่างหมดจดด้วยรหัสการออก 0 (และบางครั้งคุณไม่ต้องการข้อ จำกัด นี้) วิธีการทั้งสองนั้นไม่สามารถใช้แทนกันได้ อีกทางเลือกหนึ่งคือใช้ifคำสั่งและคุณไม่ต้องกังวลเกี่ยวกับรหัสออกจากการตรวจสอบที่ไม่มีอยู่ / ของคุณ
คิวเมนตัส

670

การทดสอบไฟล์ Bash

-b filename- บล็อกไฟล์พิเศษ
-c filename- ไฟล์อักขระพิเศษ
-d directoryname- ตรวจสอบการมีอยู่ของไดเรกทอรี
-e filename- ตรวจสอบการมีอยู่ของไฟล์โดยไม่คำนึงถึงชนิด (โหนด, ไดเรกทอรี, ซ็อกเก็ต ฯลฯ )
-f filename- ตรวจสอบการมีอยู่ของไฟล์ปกติไม่ใช่ไดเรกทอรี
-G filename- ตรวจสอบว่ามีไฟล์อยู่หรือไม่ รหัสประจำกลุ่มที่มีประสิทธิภาพ
-G filename set-group-id- เป็นจริงถ้าไฟล์มีอยู่และถูกตั้งเป็นกลุ่มรหัส
-k filename- บิตเหนียว
-L filename- ลิงก์สัญลักษณ์
-O filename- เป็นจริงถ้ามีไฟล์อยู่และเป็นเจ้าของโดย ID ผู้ใช้ที่มีประสิทธิภาพ
-r filename- ตรวจสอบว่าไฟล์อ่านได้
-S filenameหรือไม่
-s filename- ตรวจสอบว่า ไฟล์เป็นขนาดที่ไม่ใช่ศูนย์
-u filename- ตรวจสอบว่าไฟล์ set-user-id บิตถูกตั้งค่า
-w filename- ตรวจสอบว่าไฟล์เขียนได้หรือไม่
-x filename- ตรวจสอบว่าไฟล์สามารถเรียกใช้งานได้หรือไม่

วิธีใช้:

#!/bin/bash
file=./file
if [ -e "$file" ]; then
    echo "File exists"
else 
    echo "File does not exist"
fi 

แสดงออกทดสอบสามารถเมื่อตะกี้โดยใช้!ผู้ประกอบการ

#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 

1
@ 0x90 ถ้าคุณต้องการคุณมีอิสระที่จะแก้ไขโพสต์ของฉันและเพิ่มลงในรายการ ฉันเดาว่าคุณหมายถึง: -n String- ตรวจสอบว่าความยาวของสตริงไม่เป็นศูนย์หรือไม่ หรือคุณหมายถึงfile1 -nt file2- ตรวจสอบว่า file1 เป็นรุ่นที่ใหม่กว่าแล้วไฟล์ 2 (คุณยังสามารถใช้
-ot for old

1
เกี่ยวกับ -n: The unary operator -z tests for a null string, while -n or no operator at all returns True if a string is not empty.~ ibm.com/developerworks/library/l-bash-test/index.html
BlueCacti

1
เหตุใดบางคนจึงไม่เพิ่มฟังก์ชันเช่นฟังก์ชันที่มีอยู่ () {⏎ถ้า [-e "$ 1"]; จากนั้น echo "$ 1 มีอยู่" else echo "$ 1 ไม่มีอยู่" fi}
Mz A

291

คุณสามารถคัดค้านนิพจน์ด้วย "!":

#!/bin/bash
FILE=$1

if [ ! -f "$FILE" ]
then
    echo "File $FILE does not exist"
fi

man page ที่เกี่ยวข้องคือman testหรือ, หรือ, หรือman [- help testหรือhelp [สำหรับคำสั่ง bash ในตัว.


4
ในทุบตี , [เป็น builtin ดังนั้นข้อมูลที่เกี่ยวข้องจะได้รับค่อนข้างโดยhelp [... แต่นี้แสดงให้เห็นว่า[เป็นคำพ้องสำหรับการtestbuiltin help testเพราะฉะนั้นข้อมูลที่เกี่ยวข้องจะได้รับค่อนข้างโดย เห็นแล้วยังส่วนการแสดงออกทุบตีเงื่อนไขในคู่มือ
gniourf_gniourf

@gniourf_gniourf: ใช่ แต่ทุบตีในตัว[จะทำงานคำสั่งมากคล้าย ๆ กับภายนอก[คำสั่งดังนั้นทั้งman testหรือman [จะทำให้คุณมีความคิดที่ดีของวิธีการทำงาน
Keith Thompson

8
@ KeithThompson ยกเว้นว่าbash builtin [มีสวิตช์มากกว่าคำสั่งภายนอกที่[พบในระบบของฉัน ... โดยทั่วไปฉันเชื่อว่าการอ่านเอกสารที่เฉพาะเจาะจงกับเครื่องมือที่กำหนดไม่ใช่การใช้เอกสารที่เฉพาะเจาะจงกับอีกอันที่เกี่ยวข้อง ฉันอาจจะผิด แต่;)
gniourf_gniourf

134
[[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE"

นอกจากนี้ยังเป็นไปได้ว่าไฟล์นั้นเป็นลิงก์ที่ใช้งานไม่ได้หรือไฟล์ที่ไม่ปกติเช่นซ็อกเก็ตอุปกรณ์หรือ Fifo ตัวอย่างเช่นหากต้องการเพิ่มการตรวจสอบ symlink ที่ใช้งานไม่ได้:

if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!\n' "$FILE"
    else
        printf '%s does not exist!\n' "$FILE"
    fi
fi

9
ฉันขอถามหน่อยได้ไหมว่าทำไม ["" ทั้งสองในการทดสอบ? (เช่น [[! -a $ FILE]]) ฉันลองตัวเลือกทั้งหมดที่กล่าวถึงในกล่อง Solaris และมีเพียงตัวเลือกเดียวที่ใช้งานได้ขอบคุณมาก แต่ทำไม
Dimitrios Mistriotis

30
วงเล็บคู่เป็นส่วนขยาย "ทันสมัย" เช่นพวกเขาจะไม่ทำการแยกคำ (เช่นชื่อไฟล์ที่มีช่องว่าง) และยังใช้งานได้กับสตริงว่าง: mywiki.wooledge.org/BashFAQ/031
bw1024

7
ตามtldp.org/LDP/abs/html/fto.html -a เหมือนกันกับ -e มีการ "เลิกใช้แล้ว" และการใช้งานไม่ได้รับการสนับสนุน อย่างไรก็ตาม +1 ที่กล่าวถึงเพื่อตรวจสอบ symlink ที่เสียหายเช่นกัน
Luca Borrione

4
@dimitrismistriotis สอง "[" เป็นส่วนขยายที่ไม่สามารถพกพาได้ที่นำมาใช้ (ต่างกัน) โดย zsh & bash; โดยทั่วไปคุณควรหลีกเลี่ยงหากเป็นไปได้
บุคคลที่ดี

7
ฉันลงคะแนนเพราะมันใช้ [[ มันเป็นส่วนขยายที่ใช้กันอย่างแพร่หลาย หากคุณรู้ว่าคุณกำลังใช้ bash อยู่ไม่มีเหตุผลที่จะไม่ใช้มัน มันเป็นข้อผิดพลาดน้อยกว่าแนวโน้มมาก [
Michael Potter

101

เป็นมูลค่าการกล่าวขวัญว่าถ้าคุณต้องการดำเนินการคำสั่งเดียวคุณสามารถย่อ

if [ ! -f "$file" ]; then
    echo "$file"
fi

ถึง

test -f "$file" || echo "$file"

หรือ

[ -f "$file" ] || echo "$file"

ขอบคุณ! ต้องการทางเลือกที่ไม่ใช้ [[]]
Jonathan

69

ฉันชอบที่จะทำหนึ่งซับต่อไปนี้ในรูปแบบที่รองรับPOSIXเชลล์:

$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"

$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"

สำหรับสองคำสั่งเช่นฉันจะทำในสคริปต์:

$  [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}

เมื่อฉันเริ่มทำสิ่งนี้ฉันแทบจะไม่ได้ใช้ไวยากรณ์ที่พิมพ์ซ้ำทั้งหมดอีกต่อไป !!


1
ก่อนอื่นการอ้างอิงตัวแปรที่ไม่มีคำพูดจะเกิดข้อผิดพลาดได้ง่าย ที่กล่าวว่ามันพูดที่ไหนในmanpage ทุบตีใด ๆ[หรือtestในตัวจะทดสอบการมีอยู่ของไฟล์อาร์กิวเมนต์โดยค่าเริ่มต้น (เมื่อเทียบกับ-e)? จะไม่คลุมเครือหรือไม่? AFAIK (และ AIUI ส่วน "การแสดงออกตามเงื่อนไข") สิ่งเดียวที่ทดสอบด้วยวิธีการของคุณคืออาร์กิวเมนต์ไม่ว่างเปล่า (หรือไม่ได้กำหนด) ซึ่งในกรณีนี้คือการใช้คำพูดซ้ำซาก (ให้$DIR = ''และ$FILE = ''จากนั้นอาร์กิวเมนต์ยังคงอยู่'//')
แหลมปลาย

1
พิสูจน์: ผลls /foo ส่งผลให้เกิด GNU ทุบตีรุ่น 4.2.37 (1) - ปล่อย (i486-pc-linux-gnu) ls: cannot access /foo: No such file or directory[ /foo ] && echo 4242
แหลมแหลม

@PointedEars: ฉันไม่สามารถระบุ-fตัวเลือกในขณะที่ฉันเขียนคำตอบนี้ เห็นได้ชัดว่าคุณสามารถใช้งานได้ตลอดเวลา-eหากคุณไม่แน่ใจว่ามันจะเป็นไฟล์ปกติ นอกจากนี้ในสคริปต์ทั้งหมดของฉันที่ฉันพูดถึงสิ่งก่อสร้างเหล่านี้ฉันต้องส่งสิ่งนี้โดยไม่มีการพิสูจน์อักษรที่เพียงพอ
JM Becker

ACK แต่คุณอาจรู้ว่าสายการบินหนึ่งไม่สามารถแก้ไขปัญหา if-else: เกิด[ $condition ] && if_true || if_falseข้อผิดพลาดได้ง่าย ในกรณีใด ๆ ผมพบว่าง่ายต่อการอ่านและทำความเข้าใจกว่า[ ! -f "$file" ] && if_not_exists [ -f "$file" ] || if_not_exists
PointedEars

55

เพื่อทดสอบการมีอยู่ของไฟล์พารามิเตอร์สามารถเป็นอย่างใดอย่างหนึ่งต่อไปนี้:

-e: Returns true if file exists (regular file, directory, or symlink)
-f: Returns true if file exists and is a regular file
-d: Returns true if file exists and is a directory
-h: Returns true if file exists and is a symlink

การทดสอบด้านล่างทั้งหมดนำไปใช้กับไฟล์ไดเรกทอรีและ symlink ปกติ:

-r: Returns true if file exists and is readable
-w: Returns true if file exists and is writable
-x: Returns true if file exists and is executable
-s: Returns true if file exists and has a size > 0

สคริปต์ตัวอย่าง:

#!/bin/bash
FILE=$1

if [ -f "$FILE" ]; then
   echo "File $FILE exists"
else
   echo "File $FILE does not exist"
fi

39

คุณสามารถทำได้:

[[ ! -f "$FILE" ]] && echo "File doesn't exist"

หรือ

if [[ ! -f "$FILE" ]]; then
    echo "File doesn't exist"
fi

หากคุณต้องการที่จะตรวจสอบไฟล์และโฟลเดอร์ทั้งสองแล้วใช้ตัวเลือกแทน-e ผลตอบแทนจริงสำหรับไฟล์ไดเรกทอรีซ็อกเก็ตไฟล์พิเศษของตัวละครบล็อกไฟล์พิเศษ ฯลฯ-f-e


1
ที่ไม่เฉพาะทุบตี ไวยากรณ์มาจาก Korn เชลล์และยังมีอยู่ใน zsh และ bash มันมีข้อได้เปรียบที่ จำกัด กว่า[ยูทิลิตี้มาตรฐานที่นี่แม้ว่า
Stephane Chazelas

ปกติไฟล์ (เช่นเดียวกับการตรวจสอบโดย-f) และไดเรกทอรีเป็นเพียงสองของหลายประเภทของไฟล์ นอกจากนี้ยังมีซ็อกเก็ต symlinks อุปกรณ์ FIFOs ประตู ... [ -eจะทดสอบสำหรับแฟ้มการดำรงอยู่ (ของชนิดใด ๆ รวมทั้งปกติ FIFO ไดเรกทอรี ... ) หลังจากที่ความละเอียด symlink
Stephane Chazelas

@StephaneChazelas: ฉันไม่เห็นแท็ก ksh หรือ zsh ใด ๆ เรากำลังพูดถึงทุบตีหรือสิ่งที่เป็นมาตรฐานในระบบยูนิกซ์ส่วนใหญ่ ดังนั้นในบริบทมันเฉพาะทุบตี OP ไม่จำเป็นต้องรู้ทุกสิ่งที่เปลือกหอยออกมี: D
Jahid

นั่นคือความคิดเห็นในส่วน"Bash specific"ของคำตอบของคุณ
Stephane Chazelas

@StephaneChazelas: ใช่และในบริบท (ทุบตีและดวลจุดโทษมาตรฐาน) มันทุบตีเฉพาะ ฉันไม่เห็นประเด็นในความคิดเห็นที่สองของคุณมันเป็นเรื่องนอกบริบททั้งหมด OP ไม่จำเป็นที่เขาต้องการ-e -f
Jahid

35

คุณควรระมัดระวังเกี่ยวกับการใช้งานtestตัวแปรที่ไม่ได้ระบุเนื่องจากอาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิด:

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1

คำแนะนำมักจะมีตัวแปรทดสอบล้อมรอบด้วยเครื่องหมายอัญประกาศคู่:

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi

8
คำแนะนำคือให้ทุกตัวแปรล้อมรอบด้วยเครื่องหมายอัญประกาศคู่เว้นแต่คุณจะรู้อย่างแน่นอนว่าคุณมีหนึ่งในกรณีที่หายากซึ่งไม่จำเป็นหรือหนึ่งในกรณีที่หายากยิ่งซึ่งเป็นอันตราย (และไม่มีนี้ไม่ได้เป็นหนึ่งของพวกเขา.)
Uwe

คุณสนใจที่จะอธิบายอย่างละเอียดว่าเหตุใดจึงไม่ใช้เครื่องหมายคำพูดคู่ มิฉะนั้นฉันไม่เห็นประโยชน์ในความคิดเห็น
artdanil

4
ฉันหมายถึง: นี่ไม่ใช่หนึ่งในกรณีที่หายากซึ่งไม่จำเป็นหรือเป็นอันตราย โปรแกรมเมอร์เชลล์ควรใช้เพื่อใส่ (เกือบ) ตัวแปรทุกตัวในเครื่องหมายคำพูดคู่ กฎนี้ไม่ได้ [ ... ]จำกัด
Uwe


24

มีสามวิธีที่แตกต่างในการทำสิ่งนี้:

  1. ยกเลิกสถานะการออกด้วย bash (ไม่มีคำตอบอื่นใดที่กล่าวมานี้):

    if ! [ -e "$file" ]; then
        echo "file does not exist"
    fi

    หรือ:

    ! [ -e "$file" ] && echo "file does not exist"
  2. ปฏิเสธการทดสอบภายในคำสั่งทดสอบ[(นั่นคือวิธีที่คำตอบส่วนใหญ่นำเสนอมาก่อน):

    if [ ! -e "$file" ]; then
        echo "file does not exist"
    fi

    หรือ:

    [ ! -e "$file" ] && echo "file does not exist"
  3. ดำเนินการกับผลลัพธ์ของการทดสอบว่าเป็นค่าลบ ( ||แทน&&):

    เท่านั้น:

    [ -e "$file" ] || echo "file does not exist"

    นี่ดูโง่ (IMO) อย่าใช้มันยกเว้นว่าโค้ดของคุณจะต้องพกพาไปที่บอร์นเชลล์ (เช่น/bin/shโซลาริส 10 หรือเก่ากว่า) ที่ขาดโอเปอเรเตอร์การปฏิเสธ ( !):

    if [ -e "$file" ]; then
        :
    else
        echo "file does not exist"
    fi

ความแตกต่างของการพกพาระหว่าง! [และ[ !?
Flame แช่แข็ง

3
! [ เป็น POSIX เปลือกท่อ 2.9.2 (คำสั่งใด ๆ ) Otherwise, the exit status shall be the logical NOT of the exit status of the last commandและ[ ! เป็น POSIX สำหรับการทดสอบ ! expression True if expression is false. False if expression is true.ดังนั้นทั้งสอง POSIX และในประสบการณ์ของผมทั้งสองได้รับการสนับสนุนอย่างกว้างขวาง

1
@ FrozenFlame เชลล์ Bourne ไม่มี!คำหลักที่แนะนำโดย Korn เชลล์ ยกเว้นบางทีสำหรับ Solaris 10 และเก่ากว่าคุณไม่น่าจะเจอกับ Bourne shell ในสมัยนี้
Stephane Chazelas

22

ใน

[ -f "$file" ]

[คำสั่งไม่ได้stat()(ไม่ได้lstat()) สายระบบบนเส้นทางที่เก็บไว้ใน$fileและผลตอบแทนที่แท้จริงว่าระบบโทรประสบความสำเร็จและประเภทของไฟล์ที่ส่งกลับโดยstat()เป็น " ปกติ "

ดังนั้นหาก[ -f "$file" ]คืนค่าเป็นจริงคุณสามารถบอกได้ว่าไฟล์นั้นมีอยู่จริงและเป็นไฟล์ปกติหรือ symlink จะแก้ไขเป็นไฟล์ปกติในที่สุด (หรืออย่างน้อยก็เป็นตอนนั้นstat())

อย่างไรก็ตามถ้ามันกลับมา เท็จ (หรือถ้า[ ! -f "$file" ]หรือ! [ -f "$file" ]กลับจริง) มีความเป็นไปได้ที่แตกต่างกัน:

  • ไฟล์ไม่มีอยู่
  • มีไฟล์อยู่ แต่ไม่ใช่ไฟล์ปกติ (อาจเป็นอุปกรณ์, Fifo, ไดเรกทอรี, ซ็อกเก็ต ... )
  • มีไฟล์อยู่ แต่คุณไม่มีสิทธิ์ในการค้นหาในไดเรกทอรีหลัก
  • ไฟล์มีอยู่ แต่เส้นทางที่จะเข้าถึงนั้นยาวเกินไป
  • ไฟล์นี้เป็น symlink ไปยังไฟล์ปกติ แต่คุณไม่ได้รับอนุญาตให้ค้นหาในบางไดเรกทอรีที่เกี่ยวข้องกับการแก้ปัญหาของ symlink
  • ... เหตุผลอื่นใดสาเหตุที่การstat()เรียกระบบอาจล้มเหลว

กล่าวโดยย่อคือ:

if [ -f "$file" ]; then
  printf '"%s" is a path to a regular file or symlink to regular file\n' "$file"
elif [ -e "$file" ]; then
  printf '"%s" exists but is not a regular file\n' "$file"
elif [ -L "$file" ]; then
  printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file"
else
  printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file"
fi

หากต้องการทราบว่าไฟล์นั้นไม่มีอยู่จริงเราจะต้องstat()เรียกใช้ระบบเพื่อส่งคืนพร้อมรหัสข้อผิดพลาดของENOENT( ENOTDIRบอกเราว่าหนึ่งในองค์ประกอบของพา ธ ไม่ใช่ไดเรกทอรีคือกรณีอื่นที่เราสามารถบอกได้ว่าไฟล์ไม่ได้ มีอยู่โดยเส้นทางนั้น) น่าเสียดายที่[คำสั่งไม่แจ้งให้เราทราบ มันจะกลับเท็จว่ารหัสข้อผิดพลาดคือ ENOENT, EACCESS (สิทธิ์ปฏิเสธ), ENAMETOOLONG หรือสิ่งอื่นใด

ทดสอบยังสามารถทำได้ด้วย[ -e "$file" ] ls -Ld -- "$file" > /dev/nullในกรณีนั้นlsจะบอกคุณว่าทำไมความstat()ล้มเหลวถึงแม้ว่าข้อมูลจะไม่สามารถใช้โปรแกรมได้อย่างง่ายดาย:

$ file=/var/spool/cron/crontabs/root
$ if [ ! -e "$file" ]; then echo does not exist; fi
does not exist
$ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi
ls: cannot access '/var/spool/cron/crontabs/root': Permission denied
stat failed

อย่างน้อยก็lsบอกฉันไม่ได้เพราะไฟล์ไม่มีอยู่ว่ามันล้มเหลว เป็นเพราะไม่สามารถบอกได้ว่ามีไฟล์อยู่หรือไม่ [คำสั่งเพียงละเลยปัญหา

ด้วยzshเชลล์คุณสามารถค้นหารหัสข้อผิดพลาดด้วย$ERRNOตัวแปรพิเศษหลังจาก[คำสั่งที่ล้มเหลวและถอดรหัสหมายเลขนั้นโดยใช้$errnosอาร์เรย์พิเศษในzsh/systemโมดูล:

zmodload zsh/system
ERRNO=0
if [ ! -f "$file" ]; then
  err=$ERRNO
  case $errnos[err] in
    ("") echo exists, not a regular file;;
    (ENOENT|ENOTDIR)
       if [ -L "$file" ]; then
         echo broken link
       else
         echo does not exist
       fi;;
    (*) syserror -p "can't tell: " "$err"
  esac
fi

(ระวังการ$errnosสนับสนุนถูกทำลายด้วยบางรุ่นzshเมื่อสร้างขึ้นด้วยรุ่นล่าสุดของgcc )


11

หากต้องการย้อนกลับการทดสอบให้ใช้ "!" นั่นเท่ากับตัวดำเนินการเชิงตรรกะ "ไม่" ในภาษาอื่น ลองสิ่งนี้:

if [ ! -f /tmp/foo.txt ];
then
    echo "File not found!"
fi

หรือเขียนด้วยวิธีที่แตกต่างกันเล็กน้อย:

if [ ! -f /tmp/foo.txt ]
    then echo "File not found!"
fi

หรือคุณสามารถใช้:

if ! [ -f /tmp/foo.txt ]
    then echo "File not found!"
fi

หรือรวมตัวกันทั้งหมด:

if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi

ซึ่งอาจเขียน (ใช้ตัวดำเนินการ "และ": &&) เป็น:

[ ! -f /tmp/foo.txt ] && echo "File not found!"

ซึ่งดูเหมือนสั้นกว่านี้:

[ -f /tmp/foo.txt ] || echo "File not found!"




6

เชลล์สคริปต์นี้ยังสามารถค้นหาไฟล์ในไดเรกทอรี:

echo "enter file"

read -r a

if [ -s /home/trainee02/"$a" ]
then
    echo "yes. file is there."
else
    echo "sorry. file is not there."
fi

3
ไม่ชัดเจนว่าจะเพิ่มสิ่งใดก็ตามที่ยังไม่ได้รับคำตอบ มันยากรหัสชื่อพา ธ เนื่องจากคำถามถูกติดแท็กbashจึงสามารถใช้read -p "Enter file name: " -r aเพื่อแจ้งและอ่านได้ มันใช้เครื่องหมายคำพูดรอบ ๆ ตัวแปร ดี แต่ควรอธิบาย มันอาจจะดีกว่าถ้ามันสะท้อนชื่อไฟล์ และนี่เป็นการตรวจสอบว่าไฟล์นั้นมีอยู่และไม่ว่างเปล่า (นั่นคือความหมาย-s) ในขณะที่คำถามถามเกี่ยวกับไฟล์ใด ๆ ว่างเปล่าหรือไม่ (ซึ่ง-fเหมาะสมกว่า)
Jonathan Leffler

4

บางครั้งอาจมีประโยชน์ในการใช้ && และ || ผู้ประกอบการ

กดไลค์ใน (ถ้าคุณมีคำสั่ง "ทดสอบ"):

test -b $FILE && echo File not there!

หรือ

test -b $FILE || echo File there!

2

หากคุณต้องการใช้testแทนคุณ[]สามารถใช้!เพื่อคัดค้าน:

if ! test "$FILE"; then
  echo "does not exist"
fi

0

คุณยังสามารถจัดกลุ่มหลายคำสั่งในหนึ่งซับ

[ -f "filename" ] || ( echo test1 && echo test2 && echo test3 )

หรือ

[ -f "filename" ] || { echo test1 && echo test2 && echo test3 ;}

หากชื่อไฟล์ไม่ออกผลลัพธ์จะเป็น

test1
test2
test3

หมายเหตุ: (... ) ทำงานในเชลล์ย่อย {... ;} ทำงานในเชลล์เดียวกัน สัญกรณ์วงเล็บปีกกาทำงานในทุบตีเท่านั้น


1
ไม่สัญกรณ์วงเล็บปีกกาไม่ได้เป็นbash-only; มันทำงานในเปลือกที่สอดคล้องกับ POSIX ใด ๆ
Charles Duffy

0
envfile=.env

if [ ! -f "$envfile" ]
then
    echo "$envfile does not exist"
    exit 1
fi

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