ตรวจสอบว่าไฟล์อยู่ในกระบวนการของการเขียน?


25

ฉันต้องการปรับใช้กระบวนการอัตโนมัติ (ผ่านสคริปต์ cron 1 นาที) ที่ค้นหาไฟล์ tar ในไดเรกทอรีที่ระบุ หากพบไฟล์ tar ไฟล์นั้นจะถูก untarred ไปยังตำแหน่งที่เหมาะสมจากนั้นไฟล์ tar จะถูกลบ

ไฟล์ tar จะถูกคัดลอกไปยังเซิร์ฟเวอร์นี้โดยอัตโนมัติผ่าน SSH จากเซิร์ฟเวอร์อื่น ในบางกรณีไฟล์ tar มีขนาดใหญ่มากพร้อมไฟล์จำนวนมาก

ปัญหาที่ฉันคาดว่าจะพบ: หากใช้เวลา> 1 นาทีเพื่อให้คัดลอกไฟล์ tar ไปยังเซิร์ฟเวอร์และสคริปต์ cron ทำงานทุก ๆ นาทีก็จะเห็นไฟล์. tar.gz และลองทำ untar มันแม้ว่าไฟล์ tar ยังอยู่ในขั้นตอนการเขียน

มีวิธีใดบ้าง (ผ่านคำสั่ง bash) เพื่อทดสอบว่าไฟล์นั้นกำลังถูกเขียนไปหรือไม่หรือเป็นเพียงไฟล์บางส่วนเท่านั้น?

อีกทางเลือกหนึ่งที่ฉันคิดว่าคือการคัดลอกไฟล์เป็นนามสกุลไฟล์อื่น (เช่น.tar.gz.part) แล้วเปลี่ยนชื่อเป็น.tar.gzหลังจากการถ่ายโอนเสร็จสมบูรณ์ แต่ฉันคิดว่าฉันพยายามที่จะคิดออกว่ามีเพียงวิธีการตรวจสอบว่าไฟล์ทั้งหมดที่บรรทัดคำสั่งแรก ... เบาะแสใด ๆ ?


2
ไฟล์กำลังถูกโอนย้ายอย่างไร? ตัวอย่างเช่นrsyncใช้ชื่อไฟล์ชั่วคราวในระหว่างการถ่ายโอน (โดยค่าเริ่มต้น) และหลังจากโอนไฟล์อย่างสมบูรณ์แล้วให้เปลี่ยนชื่อเป็นชื่อไฟล์จริง
Piskvor

คำตอบ:


12

คุณกำลังติดตามถูกต้องการเปลี่ยนชื่อไฟล์เป็นการดำเนินการแบบปรมาณูดังนั้นการดำเนินการเปลี่ยนชื่อหลังจากอัปโหลดนั้นเรียบง่ายสวยงามและไม่เกิดข้อผิดพลาดได้ง่าย อีกวิธีที่ฉันคิดได้คือใช้lsof | grep filename.tar.gzเพื่อตรวจสอบว่าไฟล์นั้นถูกเข้าถึงโดยกระบวนการอื่นหรือไม่


7
( lsof filename.tar.gzมีประสิทธิภาพมากขึ้นและแม่นยำยิ่งกว่าlsof | grep filename.tar.gz)
Rich

BTW มันควรเป็นเส้นทางที่แน่นอนของชื่อไฟล์
DennisLi

14

ทางออกที่ดีที่สุดของคุณคือการใช้lsofเพื่อตรวจสอบว่ามีการเปิดไฟล์โดยกระบวนการใด ๆ หรือไม่:

#  lsof -f -- /var/log/syslog
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog

คุณไม่สามารถบอกได้อย่างง่ายดายว่ามันกำลังอยู่ในขั้นตอนการเขียน แต่ถ้ามันกำลังถูกเขียนไปมันจะต้องเปิดอยู่


แก้ไข: ลองแก้ปัญหาจริงที่นี่แทนที่จะลองใช้วิธีแก้ปัญหาที่เสนอ!

ใช้ rsync เพื่อถ่ายโอนไฟล์:

  rsync -e ssh remote:big.tar.gz .

ด้วยวิธีนี้ไฟล์จะไม่ถูกคัดลอกไปด้านบนของไฟล์ที่มีอยู่ แต่คัดลอกลงในไฟล์ชั่วคราว ( .big.tar.gz.XXXXXX) จนกว่าการถ่ายโอนจะเสร็จสมบูรณ์จากนั้นจึงย้ายเข้าที่


6

ค่อนข้างเก่า แต่คำตอบส่วนใหญ่หายไปจากจุดคำถามอย่างสมบูรณ์:

แต่ฉันคิดว่าฉันพยายามที่จะคิดออกว่ามีเพียงวิธีการตรวจสอบว่าไฟล์ทั้งหมดที่บรรทัดคำสั่งแรก ...

โดยทั่วไปแล้วไม่มี คุณมีข้อมูลไม่เพียงพอที่จะพิจารณาได้

เพราะการกำหนดว่าไฟล์ที่ปิดไม่ได้เป็นเช่นเดียวกับการกำหนดว่าไฟล์เป็นทั้ง ตัวอย่างเช่นไฟล์จะได้รับ "ปิด" หากการเชื่อมต่อหายไประหว่างการถ่ายโอน

เฉพาะคำตอบของ @ Alex เท่านั้นที่ได้รับสิทธิ์นี้ และถึงแม้เขาจะตกหลุมการใช้งานlsofบ้าง

หากต้องการตรวจสอบว่าไฟล์ถูกถ่ายโอนอย่างสมบูรณ์หรือไม่จำเป็นต้องมีข้อมูลเพิ่มเติม เช่น:

อีกทางเลือกหนึ่งที่ฉันคิดว่าคือการคัดลอกไฟล์เป็นนามสกุลไฟล์อื่น (เช่น.tar.gz.part) แล้วเปลี่ยนชื่อเป็น.tar.gzหลังจากการถ่ายโอนเสร็จสมบูรณ์

นี่เป็นวิธีที่ดีที่สุดในการสื่อสารว่าไฟล์ได้รับการถ่ายโอนอย่างสมบูรณ์และสำเร็จแล้ว คุณยังสามารถย้ายไฟล์จากไดเรกทอรีหนึ่งไปยังอีกไดเรกทอรีหนึ่งตราบเท่าที่คุณอยู่ในระบบไฟล์เดียวกัน หรือให้ผู้ส่งส่งfilename.doneไฟล์เปล่าเพื่อส่งสัญญาณให้เสร็จ

แต่วิธีการทั้งหมดต้องพึ่งพาผู้ส่งสัญญาณว่าการถ่ายโอนเสร็จสมบูรณ์ เพราะมีเพียงผู้ส่งเท่านั้นที่มีข้อมูลนั้น

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

lsofจะบอกให้คุณทราบว่าไฟล์นั้นไม่ได้เปิดอีกต่อไป - มันจะไม่บอกคุณว่าทำไมมันถึงไม่เปิดอีกต่อไป และจะไม่บอกว่าไฟล์ควรใหญ่แค่ไหน


1
ฉันไม่สามารถลงคะแนนได้เพียงพอ เก่งในการแก้ปัญหา XY ที่นี่
Beefster

5

วิธีที่ดีที่สุดในการทำเช่นนี้คือใช้incron ("inotify ระบบ cron") จะช่วยให้คุณสามารถตั้งค่าinotify watch ในไดเรกทอรีซึ่งจะแจ้งให้คุณทราบถึงการทำงานของไฟล์ ในกรณีนี้คุณควรดู dir สำหรับ close_write ที่จะให้คุณเรียกใช้คำสั่งของคุณเมื่อไฟล์ถูกปิดหลังจากการเขียน


2

ดูเหมือนว่า lsof สามารถตรวจพบโหมดของไฟล์ที่เปิดอยู่:

lsof -f -- a_file
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     52391 bob    1w   REG    1,2       15 19545007 a_file

ดูว่ามันบอกว่า 1w นั่นหมายความว่าหมายเลขตัวอธิบายไฟล์คือ 1 และโหมดคือ w หรือเขียน


FDแสดงข้อมูล3rสำหรับฉันเมื่อไฟล์ถูกเปิดสำหรับการอ่าน
Sopalajo de Arrierez

0

การใช้inotifywaitสามารถบรรลุสิ่งที่คุณต้องการ - มีความสามารถในการรอจนกว่าการเขียนไฟล์จะเสร็จสิ้นก่อนที่จะดำเนินการคำสั่ง

ต่อไปนี้จะดูโฟลเดอร์สำหรับไฟล์ใหม่อย่างต่อเนื่องและดำเนินการคำสั่งในลูปเมื่อการเขียนไปยังไฟล์เสร็จสิ้น

WATCH_DIR=/directory/to/monitor
DEST_DIR=/x/y/z

/usr/bin/inotifywait --recursive --monitor --quiet -e moved_to -e close_write --format '%w%f' "$WATCH_DIR" | while read -r INPUT_FILE; do

mv "$0" "$DEST_DIR"

done

สำหรับตัวเลือกการกำหนดค่าเพิ่มเติมโปรดดูที่https://linux.die.net/man/1/inotifywatch

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