สคริปต์ตรวจสอบโฟลเดอร์สำหรับไฟล์ใหม่หรือไม่


127

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


1
คุณจะลบไฟล์ออกจากโฟลเดอร์เมื่อมีการประมวลผลหรือไม่
ztank1013

คำตอบ:


151

คุณควรพิจารณาใช้inotifywaitเป็นตัวอย่าง:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

ใน Ubuntu inotifywaitมีให้โดยinotify-toolsแพ็คเกจ ตั้งแต่เวอร์ชัน 3.13 (ปัจจุบันใน Ubuntu 12.04) inotifywaitจะรวมชื่อไฟล์โดยไม่มีตัวเลือก -f รุ่นเก่าอาจต้องมีการบีบบังคับ สิ่งสำคัญที่ควรทราบคือ-eตัวเลือกที่จะinotifywaitเป็นวิธีที่ดีที่สุดในการกรองเหตุการณ์ นอกจากนี้readคำสั่งของคุณสามารถกำหนดเอาต์พุตตำแหน่งให้เป็นตัวแปรหลายตัวที่คุณสามารถเลือกใช้หรือเพิกเฉยได้ ไม่จำเป็นต้องใช้ grep / sed / awk เพื่อประมวลผลเอาต์พุตล่วงหน้า


1
ที่ดี! นั่นinotifywaitเป็นสิ่งที่ฉันต้องการ
ihatetoregister

2
แค่ต้องการอัปเดตนี้ คุณไม่จำเป็นต้อง awk เพื่อให้บรรลุนี้ คุณสามารถกรองเหตุการณ์ด้วย '-e create' และรับเฉพาะชื่อไฟล์โดยทำ '-f% f' หรือพา ธ แบบเต็มโดยใช้ '-f% w% f' ดังนั้นบรรทัดแรกของสคริปต์ด้านบนจะกลายเป็น: inotifywait -m / path -f% w% f -e create |
Lugoues

2
@Lugoues และตอนนี้เมื่อคุณพยายามที่จะใช้ - ถ้าคุณได้รับThe '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.ดังนั้นคุณจะต้องทำinotifywait -m /path -e create |ฉันจะลองและแก้ไขคำตอบนี้
Bruno Bronosky

1
fswatchขณะนี้มียังเป็นเครื่องมือแบบพกพาสำหรับเรียกมันว่า ฉันไม่ได้เขียนมัน แต่มันเป็นโอเพ่นซอร์สและฉันใช้มัน

1
@Wender inotfiywait ส่งออกข้อมูล 3 ชิ้นในบรรทัดเดียวเมื่อถูกเรียก built-in ทุบตี 'read' อ่านบรรทัดอินพุตและกำหนดข้อมูลทั้งสามชิ้นให้กับตัวแปร ดังนั้นชิ้นแรกจะถูกกำหนดให้กับเส้นทางตัวแปรที่สองไปสู่การปฏิบัติและที่สามไปยังไฟล์ การมีค่าที่กำหนดให้กับตัวแปรเหล่านั้นจะสามารถใช้งานได้ในภายหลัง (เช่นบนเส้นเสียงก้อง) ข้อมูลเพิ่มเติม: tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Tim

26

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

Ex:

<directory> <file change mask> <command or action>  options
/var/www/html IN_CREATE /root/scripts/backup.sh

คุณสามารถดูตัวอย่างทั้งหมดได้ที่นี่: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/


24

ฉันเพิ่งทำสิ่งนี้ขึ้นมาและไม่เห็นมีปัญหากับมันเลยนอกจากมีโอกาสที่ไฟล์จะหายไประหว่างการตรวจสอบ

while true
do
       touch  ./lastwatch
       sleep 10
       find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done

หากการประมวลผลไฟล์ของคุณใช้เวลาไม่นานคุณไม่ควรพลาดไฟล์ใหม่ คุณสามารถทำกิจกรรมเบื้องหลัง ... มันไม่ได้เป็น bullet bullet แต่มันมีจุดประสงค์บางอย่างโดยไม่มีเครื่องมือภายนอกเช่น inotify


จับดี. ฉันปรับปรุงมันเล็กน้อยเพื่อรองรับช่องว่างในชื่อไฟล์
Michael Sacchi

อย่างแน่นอน นั่นคือวิธีที่จะไป ไม่แน่ใจจริงๆว่าทำไมฉันถึงลงที่ถนนฉันใช้ -exec เป็นประจำ
Michael Sacchi

มันไม่ใช่เรียลไทม์ เรียลไทม์ดีที่สุดเสมอ
Farhan

3
ทางออกที่ดีที่สุดถ้าinotifyไม่สามารถใช้ได้ ฉันจะเพิ่ม-type fเพื่อกรองไฟล์เท่านั้น มิฉะนั้นโฟลเดอร์จะถูกส่งคืน
Xiao Peng - ZenUML.com

ใช่ - -f filenameตัวเลือกยอดเยี่ยม ดังนั้นคำถามเดียวที่เหลืออยู่ก็คือจะเริ่มต้นอย่างไรเมื่อรีบูท ฉันจะใช้สิ่งนี้กับโรงงานพลังงานแสงอาทิตย์ของฉันos.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")ดังนั้นการสร้างไฟล์นี้จะทำให้คอมพิวเตอร์หลักใช้งานespeakและประกาศแรงดันไฟฟ้าต่ำ มันส่งอีเมลถึงฉันแล้ว แต่เนื่องจากระบบของฉันพูดเวลาที่ด้านบนสุดของชั่วโมงมันจึงมีเวลาที่เหลือทั้งหมด askubuntu.com/questions/977613/…
SDsolar

17

คุณสามารถใช้watchในสคริปต์ของคุณ

watch -n 0.1 ls <your_folder>

ตรวจสอบโฟลเดอร์ของคุณและแสดงรายการทุกอย่างภายใน 0.1 วินาที

ข้อเสียเปรียบ

ไม่ใช่เรียลไทม์ดังนั้นหากไฟล์ถูกสร้างและลบในเวลาน้อยกว่า 0.1 วินาทีสิ่งนี้จะไม่ทำงานwatchสนับสนุนขั้นต่ำ 0.1 วินาทีเท่านั้น


นั่นคือสิ่งที่ฉันพยายามจำ! ขอบคุณมาก!!
Joabe Lucena

9

ฉันสมมติว่าโฟลเดอร์เป้าหมาย (ฉันจะเรียกมันว่าisemptyเพื่อความสะดวกเท่านั้น) ว่างเปล่าและคุณกำลังรอไฟล์หนึ่งไฟล์หรือมากกว่านั้น

คุณสามารถใช้คำสั่งต่อไปนี้:

ls -1A isempty | wc -l

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

ที่กล่าวว่าโง่ถ้า / จากนั้นการทดสอบสามารถทำให้ส่วนที่เหลือของงาน:

if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

แน่นอนว่าdo_somethingฟังก์ชั่นจะต้องจัดการไฟล์ภายในisemptyโฟลเดอร์แล้วลบออกจากโฟลเดอร์หลังจากประมวลผล

การเพิ่มบรรทัดดังต่อไปนี้ใน crontab ของคุณจะรันการตรวจสอบหนึ่งครั้งต่อนาทีและจะทริกเกอร์การdo_somethingกระทำหากโฟลเดอร์ไม่ว่างเปล่า:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

วิธีนี้ใช้ได้กับระบบไฟล์รีโมตที่เมาท์ ผู้พัฒนา inotify-tools กำลังทำงานกับฟิวส์ (หรืออยู่ในช่วงกลางปี ​​2014)
Rondo

3
คุณไม่ควรใช้lsสำหรับการเขียนสคริปต์ ใช้findหรือ globbing ง่ายแทน: mywiki.wooledge.org/ParsingLs
andsens

6

หากคุณต้องการที่จะตรวจสอบไฟล์ใหม่แล้วดำเนินการให้และในตอนท้ายลบไฟล์ดำเนินการต่อคุณสามารถใช้systemd.path วิธีการนี้อาศัยการรู้แจ้ง มีตัวเลือก DirectoryNotEmpty ดังนั้น systemd สามารถเรียกใช้สคริปต์ของคุณได้เสมอเมื่อตรวจพบไฟล์ใด ๆ ในไดเรกทอรี คุณต้องจำไว้ว่ามันจะทำงานได้ก็ต่อเมื่อคุณสามารถลบไฟล์ที่ดำเนินการต่อไปและสคริปต์ปล่อยไดเรกทอรีว่างไว้

ก่อนอื่นให้เตรียมไฟล์ mymonitor.service

[Unit]
Description=Start the script

[Service]
Type=oneshot
ExecStart=/path/to/your/script

จากนั้นไปที่ mymonitor.path เพื่อกำหนดเส้นทาง

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

หากชื่อของไฟล์. path เหมือนกันกับชื่อของบริการไม่จำเป็นต้องระบุชื่อบริการในไฟล์. path

มันขึ้นอยู่กับการตรวจสอบการเข้าถึงไฟล์สำหรับ Dummies


4

entr

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

ใช้kqueue(2)หรือinotify(7)เพื่อหลีกเลี่ยงการเลือกตั้ง entrถูกเขียนขึ้นเพื่อให้ข้อเสนอแนะอย่างรวดเร็วและการทดสอบอัตโนมัติเป็นเรื่องธรรมดา

ใน BSD จะใช้ pledge(2)

คุณสามารถติดตั้งได้ด้วย

apt-get install entr
dnf install entr

คุณสามารถติดตามไดเรกทอรีสำหรับการเพิ่มใหม่โดยใช้

while $(true); do
  # echo ./my_watch_dir | entr -dnr echo "Running trigger..."
  echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;

ตัวเลือกที่อธิบาย (จากเอกสาร)

  • -d ติดตามไดเรกทอรีของไฟล์ปกติที่มีให้เป็นอินพุตและออกหากมีการเพิ่มไฟล์ใหม่ ตัวเลือกนี้ยังช่วยให้สามารถระบุไดเรกทอรีได้อย่างชัดเจน ไฟล์ที่มีชื่อขึ้นต้นด้วย '.' จะถูกละเว้น
  • -nทำงานในโหมดที่ไม่โต้ตอบ ในโหมดนี้ entr จะไม่พยายามอ่านจาก TTY หรือเปลี่ยนคุณสมบัติ
  • -r โหลดกระบวนการลูกถาวร เช่นเดียวกับโหมดการทำงานมาตรฐานยูทิลิตี้ที่ยกเลิกจะไม่ถูกดำเนินการอีกครั้งจนกว่าระบบไฟล์หรือเหตุการณ์แป้นพิมพ์จะถูกประมวลผล SIGTERMใช้เพื่อยกเลิกการทำงานของยูทิลิตี้ก่อนที่จะรีสตาร์ท กลุ่มกระบวนการถูกสร้างขึ้นเพื่อป้องกันเชลล์สคริปต์จากสัญญาณกำบัง entrรอยูทิลิตีเพื่อออกเพื่อให้แน่ใจว่าทรัพยากรเช่นซ็อกเก็ตถูกปิด การควบคุม TTY จะไม่ถูกโอนย้ายกระบวนการลูก

2

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

สิ่งที่คุณกำลังมองหาเรียกว่า inotify มันสร้างไว้ในเคอร์เนล linux และโดยทั่วไปคุณสามารถนั่งรอสิ่งที่เกิดขึ้นที่จุด inotify กลับมาและบอกว่า 'เฮ้มีไฟล์ใหม่ที่ชื่อว่า foobar'

เพื่อให้บรรลุสิ่งที่คุณต้องการคุณจะต้องเปลี่ยนไปใช้ภาษาอย่าง Perl และใช้ Linux :: Inotify2 (ไพ ธ อนอาจสนับสนุน inotify เช่นกัน แต่ฉันเป็นคน Perl)


0

ใช้งานได้ใน cygwin และ Linux วิธีแก้ไขปัญหาก่อนหน้าบางตัวที่เขียนไฟล์จะทำให้ดิสก์พุ่งชน ฉบับนี้ไม่มีปัญหา:

SIG=1
SIG0=$SIG
while [ $SIG != 0 ] ; do
 while [ $SIG = $SIG0 ] ; do
   SIG=`ls -1 | md5sum | cut -c1-32`
   sleep 10
 done
 SIG0=$SIG
 ls -lrt | tail -n 1
done

0

ด้านล่างเป็นตัวอย่างย่อของstackoverflowที่ฉันได้ทดสอบและรวมไว้ในหนึ่งในโครงการของฉันที่ต้องการการตรวจสอบไดเรกทอรีเฉพาะ

Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
    _added="$(grep -E '>' <<<"${@}")"
    if [ "${#_added}" != "0" ]; then
        mapfile -t _added_list <<<"${_added//> /}"
        _let _index=0
        until [ "${#_added_list[@]}" = "${_index}" ]; do
            _path_to_check="${Var_dir}/${_added_list[${_index}]}"
            if [ -f "${_path_to_check}" ]; then
                echo "# File: ${_path_to_check}"
            elif [ -d "${_path_to_check}" ]; then
                echo "# Directory: ${_path_to_check}"
            if [ -p "${_path_to_check}" ]; then
                echo "# Pipe: ${_path_to_check}"
            fi
            let _index++
        done
        unset _index
    fi
}
Func_watch_bulk_dir(){
    _current_listing=""
    while [ -d "${Var_dir}" ]; do
        _new_listing="$(ls "${Var_dir}")"
        _diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
        if [ "${_diff_listing}" != "0" ]; then
            Func_parse_diff "${_diff_listing}"
        fi
        _current_listing="${_new_listing}"
        sleep ${Var_diff_sleep}
    done
}

นี่คือลิงค์ไปยังสคริปต์ที่ใช้เวอร์ชันที่แก้ไขด้านบนเพื่อถอดรหัสไฟล์หรือไดเรกทอรีที่พบในจุดเมานท์ sshfs โดยอัตโนมัติ โครงการดังกล่าวข้างต้น

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