วิธีตรวจสอบว่ามีไฟล์อยู่ในเชลล์สคริปต์หรือไม่


175

ฉันต้องการเขียนเชลล์สคริปต์ซึ่งตรวจสอบว่ามีไฟล์บางไฟล์ที่archived_sensor_data.jsonมีอยู่และถ้าใช่จะลบออก กำลังติดตามhttp://www.cyberciti.biz/tips/find-out-if-file-exists-with-conditional-expressions.html กำลังติดตามฉันได้ลองทำสิ่งต่อไปนี้:

[-e archived_sensor_data.json] && rm archived_sensor_data.json

อย่างไรก็ตามสิ่งนี้จะพ่นข้อผิดพลาด

[-e: command not found

เมื่อฉันพยายามเรียกใช้test_controllerสคริปต์ผลลัพธ์โดยใช้./test_controllerคำสั่ง มีอะไรผิดปกติกับรหัสหรือไม่



2
คุณต้องตั้งช่องว่างหนึ่งช่องขึ้นไประหว่างการเปิดวงเล็บเหลี่ยม "[" และตัวเลือก "-e" เหมือนกับระหว่างชื่อไฟล์และวงเล็บเหลี่ยมปิด "]"
Konstantin Yaniv

คำตอบ:


350

คุณไม่มีช่องว่างระหว่างวงเล็บและ-e:

#!/bin/bash
if [ -e x.txt ]
then
    echo "ok"
else
    echo "nok"
fi

12
[ -e archived_sensor_data.json ] && rm archived_sensor_data.jsonในที่สุดผมก็เพิ่มอีกสองช่องว่างหนึ่งหลังจากตารางวงเล็บเปิดและหนึ่งก่อนที่จะปิดหนึ่ง: ดูเหมือนว่าสคริปต์จะใช้งานได้ในขณะนี้
Kurt Peek

3
นอกจากนี้ยังสามารถใช้งานได้if [ -e "$1" ](อาร์กิวเมนต์การป้อนชื่อไฟล์)
Edward

2
ข้อแตกต่างที่สำคัญที่นี่คือความจริงที่ว่าคุณกำลังใช้สคริปต์ "ทุบตี" แทนการเขียนสคริปต์ "เชลล์" โปรดสังเกตว่าบรรทัดแรกที่คุณเพิ่มคือ #! / bin / bash ดังนั้นคุณจึงบอกให้เครื่องใช้ "bash" แทน sh เนื่องจาก sh ไม่รู้จักอาร์กิวเมนต์นั้น "-e"
Nick Cuevas

29

นี่คือวิธีทางเลือกโดยใช้ls:

(ls x.txt && echo yes) || echo no

หากคุณต้องการซ่อนเอาต์พุตใด ๆlsเพื่อให้คุณเห็นว่าใช่หรือไม่ใช่ให้เปลี่ยนเส้นทางstdoutและstderrไปที่/dev/null:

(ls x.txt >> /dev/null 2>&1 && echo yes) || echo no

1
รหัสนี้หมายถึง: "ถ้าlsสำเร็จไฟล์ดังกล่าวมิฉะนั้นจะไม่มี" หากlsล้มเหลวก็ไม่ได้หมายความว่าไฟล์นั้นหายไป อาจเป็นข้อผิดพลาดอื่น ๆ ตัวอย่างเช่นสร้างไฟล์ในไดเร็กทอรีที่ root เป็นเจ้าของและพยายามทำlsภายใต้ผู้ใช้ทั่วไป มันจะล้มเหลวด้วยPermission deniedซึ่งไม่เท่ากับไฟล์ที่ไม่มีอยู่
Tigran

9

คำแนะนำในการแก้ไขปัญหาเบื้องหลังของฉันคือเรื่องราวของเพื่อนที่เข้าสู่สัปดาห์ที่สองของงานแรกของเขาเช็ดครึ่งงานสร้างเซิร์ฟเวอร์ที่สะอาด ดังนั้นงานพื้นฐานคือการพิจารณาว่ามีไฟล์อยู่หรือไม่ถ้าอย่างนั้นเราจะลบมันทิ้ง แต่มีกระแสน้ำเชี่ยวที่เป็นอันตรายอยู่เล็กน้อยในแม่น้ำนี้:

  • ทุกอย่างเป็นไฟล์

  • สคริปต์มีพลังที่แท้จริงก็ต่อเมื่อพวกเขาแก้ไขงานทั่วไป

  • โดยทั่วไปเราใช้ตัวแปร

  • เรามักจะใช้ -f บังคับในสคริปต์เพื่อหลีกเลี่ยงการแทรกแซงด้วยตนเอง

  • และยังรัก -r ซ้ำเพื่อให้แน่ใจว่าเราสร้างคัดลอกและทำลายในเวลาที่เหมาะสม

พิจารณาสถานการณ์สมมติต่อไปนี้:

เรามีไฟล์ที่เราต้องการลบ: filesexists.json

ชื่อไฟล์นี้ถูกเก็บไว้ในตัวแปร

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

เรายังมีตัวแปรพา ธ เพื่อทำให้สิ่งต่างๆมีความยืดหยุ่น

<host>:~/Documents/thisfolderexists pathtofile=".."

<host>:~/Documents/thisfolderexists ls $pathtofile

filesexists.json  history20170728  SE-Data-API.pem  thisfolderexists

งั้นลองดูว่า-eทำตามที่ควรจะเป็นหรือไม่ มีไฟล์อยู่หรือไม่

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

มันทำ มายากล.

อย่างไรก็ตามจะเกิดอะไรขึ้นถ้าตัวแปรไฟล์ได้รับการประเมินโดยไม่ตั้งใจให้เป็นนัฟฟิน

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

อะไร? มันควรจะกลับมาพร้อมกับข้อผิดพลาด ... และนี่คือจุดเริ่มต้นของเรื่องราวที่ว่าโฟลเดอร์ทั้งหมดถูกลบโดยไม่ตั้งใจ

ทางเลือกอื่นอาจเป็นการทดสอบเฉพาะสิ่งที่เราเข้าใจว่าเป็น 'ไฟล์'

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

0

ดังนั้นไฟล์ที่มีอยู่ ...

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

1

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

man test มีดังต่อไปนี้จะพูดว่า:

-b FILE

       FILE exists and is block special

-c FILE

       FILE exists and is character special

-d FILE

       FILE exists and is a directory

-e FILE

       FILE exists

-f FILE

       FILE exists and is a regular file

...

-h FILE

       FILE exists and is a symbolic link (same as -L)

4

ภายในคำสั่ง rm ต้องทดสอบการมีอยู่ของไฟล์อยู่แล้ว
เหตุใดจึงต้องเพิ่มการทดสอบอื่น เพียงแค่ออก

rm filename

และหลังจากนั้นไม่ว่าจะอยู่ที่นั่นหรือไม่ก็ตาม
ใช้ rm -f คือคุณไม่ต้องการข้อความใด ๆ เกี่ยวกับไฟล์ที่ไม่มีอยู่

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


1
นี่เป็นคำตอบที่ถูกต้องสำหรับคำสั่ง rm สำหรับคำสั่งอื่น ๆ ฉันแนะนำให้ทำการทดสอบด้วย -e
warhansen

ยกเว้นว่าไม่ใช่คำถามที่ถาม
ดินสอสี

1
มันเป็นสิ่งที่คำถามถามถ้าคุณอ่านคำถามทั้งหมดรวมถึงส่วน "... และ (ถ้าเป็นเช่นนั้น) ... ลบมัน"
TG

1

หากคุณกำลังใช้ NFS "test" เป็นวิธีแก้ปัญหาที่ดีกว่าเพราะคุณสามารถเพิ่มการหมดเวลาได้ในกรณีที่ NFS ของคุณไม่ทำงาน:

time timeout 3 test -f 
/nfs/my_nfs_is_currently_down
real    0m3.004s <<== timeout is taken into account
user    0m0.001s
sys     0m0.004s
echo $?
124   <= 124 means the timeout has been reached

การสร้าง "[-e my_file]" จะหยุดจนกว่า NFS จะทำงานอีกครั้ง:

if [ -e /nfs/my_nfs_is_currently_down ]; then echo "ok" else echo "ko" ; fi

<no answer from the system, my session is "frozen">

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