ในขณะที่วนซ้ำเพื่อทดสอบว่ามีไฟล์อยู่ใน bash หรือไม่


97

ฉันกำลังทำงานกับเชลล์สคริปต์ที่ทำการเปลี่ยนแปลงบางอย่างในไฟล์ txt เฉพาะในกรณีที่มีอยู่อย่างไรก็ตามลูปทดสอบนี้ใช้ไม่ได้ฉันสงสัยว่าทำไม? ขอบคุณ!

while [ ! -f /tmp/list.txt ] ;
do
      sleep 2
done

3
ฉันไม่สามารถพูดได้ว่าฉันประหลาดใจ; ลูปนั้นไม่ได้พยายามเปลี่ยนแปลงอะไรเลย
Ignacio Vazquez-Abrams

เซมิโคลอนซ้ำซ้อน ลูปทดสอบนั้นไม่ทำงานในลักษณะใด มันจะนอนซ้ำ ๆ เป็นเวลา 2 วินาทีจนกว่าไฟล์ /tmp/list.txt จะมีอยู่
Jonathan Leffler

5
ใช้งานได้สำหรับฉัน - ลูปจะสิ้นสุดเมื่อไฟล์ถูกสร้างขึ้นนอกสคริปต์

1
ในความเป็นจริงลูปนี้ทำหน้าที่รอจนกว่าไฟล์จะอยู่ที่นั่นสคริปต์ที่เหลือของฉันจะทำการเปลี่ยนแปลง ... : p
Zenet

1
จากนั้นลูปในขณะทำงานก็แค่ฉัน ... ขอโทษ
Zenet

คำตอบ:


149

เมื่อคุณพูดว่า "ใช้ไม่ได้" คุณจะรู้ได้อย่างไรว่ามันใช้ไม่ได้?

คุณอาจลองดูว่าไฟล์นั้นมีอยู่จริงหรือไม่โดยเพิ่ม:

while [ ! -f /tmp/list.txt ]
do
  sleep 2 # or less like 0.2
done
ls -l /tmp/list.txt

คุณอาจตรวจสอบให้แน่ใจว่าคุณใช้ Bash (หรือที่เกี่ยวข้อง) เชลล์โดยพิมพ์ 'echo $ SHELL' ฉันคิดว่า CSH และ TCSH ใช้ความหมายที่แตกต่างกันเล็กน้อยสำหรับลูปนี้


ทำไมคุณถึงใช้การตรวจสอบไฟล์กลับหัว ในขณะที่ไม่ควรใช้ [-f /tmp/list.txt] แทน
valentt

2
@valentt ไม่ต้องวนลูปพูดตามตัวอักษรว่า "ในขณะที่ไม่มีไฟล์อยู่ให้นอน" .. ถ้าคุณลบ 'NOT' วงจะแตกทันที
เคนยกรณ์เกตุสมบัติ

2
ใน 1 บรรทัด:while [ ! -f /tmp/list.txt ]; do sleep 2; done; ls -l /tmp/list.txt
DrumM

55

หากคุณใช้ linux และติดตั้ง inotify-tools ไว้คุณสามารถทำได้:

file=/tmp/list.txt
while [ ! -f "$file" ]
do
    inotifywait -qqt 2 -e create -e moved_to "$(dirname $file)"
done

ซึ่งจะช่วยลดความล่าช้าที่เกิดจากการนอนหลับขณะที่ยังคงสำรวจทุกๆ "x" วินาที คุณสามารถเพิ่มกิจกรรมอื่น ๆ ได้หากคุณคาดว่าจำเป็น


4
+1 เพื่อประสิทธิภาพ การนอนหลับเป็นเรื่องน่าเกลียด สำหรับคนที่ไม่รู้จัก inotifywait - มันอยู่ในแพ็คเกจ inotify-tools
MichałŠrajer

7
เป็นเครื่องมือที่มีประโยชน์มาก สำหรับใครที่สงสัยว่าทำไมต้องวนซ้ำการจัดการกับเงื่อนไขการแข่งขันที่เป็นไปได้ระหว่างการสร้างและการรอและเนื่องจาก inotifywait --excludeต้องกรองชื่อไฟล์ออก แต่--includeต้องไม่เพิกเฉยต่อทุกสิ่งยกเว้นชื่อไฟล์ คำสั่งดังกล่าวควรใช้-qqอาร์กิวเมนต์แทน>&/dev/nullแม้ว่า
Craig Ringer

t คือ--timeoutความถี่ในการตรวจสอบไม่ใช่หรือ? ประเด็นของ inotifywait คือไม่มีการหยั่งเสียง
Alex Dean

1
@AlexDean การหมดเวลาคือการป้องกันสภาวะการแข่งขัน การสำรวจด้วยโหมดสลีปจะช้าเนื่องจากลูปจะไม่ออกในระหว่างการนอนหลับ แต่ inotifywait จะออกก่อนหมดเวลาหากเห็นเหตุการณ์
yingted

1
@AlexDean ใช่ แต่จำเป็นต้องป้องกันสภาพการแข่งขัน TOCTTOU มิฉะนั้นinotifywaitอาจแฮงค์ไปเรื่อย ๆ หากไฟล์ถูกสร้างขึ้นก่อนที่จะเริ่มฟังเหตุการณ์
yingted

4

ฉันมีปัญหาเดียวกันใส่! นอกวงเล็บ;

while ! [ -f /tmp/list.txt ];
do
    echo "#"
    sleep 1
done

นอกจากนี้หากคุณเพิ่มเสียงสะท้อนภายในลูปมันจะบอกคุณว่าคุณกำลังเข้าสู่ลูปหรือไม่


2

ฉันพบปัญหาที่คล้ายกันและมันทำให้ฉันมาที่นี่ดังนั้นฉันแค่อยากจะทิ้งวิธีแก้ปัญหาไว้สำหรับทุกคนที่ประสบปัญหาเดียวกัน

ฉันพบว่าถ้าฉันรันcat /tmp/list.txtไฟล์จะว่างเปล่าแม้ว่าฉันจะแน่ใจว่ามีเนื้อหาถูกวางไว้ในไฟล์ทันที ปรากฎว่าถ้าฉันใส่sleep 1;ก่อนที่cat /tmp/list.txtมันจะทำงานตามที่คาดไว้ ต้องมีความล่าช้าระหว่างเวลาที่สร้างไฟล์และเวลาที่เขียนหรือมีบางอย่างตามบรรทัดเหล่านั้น

รหัสสุดท้ายของฉัน:

while [ ! -f /tmp/list.txt ];
do
    sleep 1;
done;
sleep 1;
cat /tmp/list.txt;

หวังว่านี่จะช่วยประหยัดเวลาครึ่งชั่วโมงที่น่าผิดหวังของใครบางคน!


1

เช่นเดียวกับ @ zane-hooper ฉันมีปัญหาคล้ายกันใน NFS บนระบบไฟล์แบบขนาน / แบบกระจายความล่าช้าระหว่างคุณสร้างไฟล์ในเครื่องหนึ่งและอีกเครื่อง "เห็น" ไฟล์อาจมีขนาดใหญ่มากดังนั้นฉันจึงสามารถรอได้ถึงหนึ่งนาทีเต็มหลังจากสร้างไฟล์ก่อนที่ลูป while จะออก (และ นอกจากนี้ยังมีผลที่ตามมาจากการ "เห็น" ไฟล์ที่ลบไปแล้ว)

สิ่งนี้สร้างภาพลวงตาว่าสคริปต์ "ใช้งานไม่ได้"ในขณะที่จริงๆแล้วมันเป็นระบบไฟล์ที่ปล่อยลูกบอล

ฉันใช้เวลาพอสมควรในการคิดออกหวังว่ามันจะช่วยใครสักคนได้บ้าง

ป.ล. สิ่งนี้ทำให้เกิดข้อผิดพลาด "ตัวจัดการไฟล์เก่า" ที่น่ารำคาญ


0

ทำงานร่วมกับ bash และ sh ทั้งสอง:

touch /tmp/testfile
sleep 10 && rm /tmp/testfile &
until ! [ -f /tmp/testfile ]
do
   echo "testfile still exist..."
   sleep 1
done
echo "now testfile is deleted.."

0

นี่คือเวอร์ชันที่มีการหมดเวลาดังนั้นหลังจากผ่านไประยะหนึ่งลูปจะสิ้นสุดลงด้วยข้อผิดพลาด:

# After 60 seconds the loop will exit
timeout=60

while [ ! -f /tmp/list.txt ];
do
  # When the timeout is equal to zero, show an error and leave the loop.
  if [ "$timeout" == 0 ]; then
    echo "ERROR: Timeout while waiting for the file /tmp/list.txt."
    exit 1
  fi

  sleep 1

  # Decrease the timeout of one
  ((timeout--))
done

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