新しいファイルのフォルダーを監視するスクリプト?


127

スクリプトを使用してフォルダー内の新しいファイルを検出する方法は?ファイルがフォルダーに作成されたらすぐに処理したいと思います。これを行うことは可能ですか、それとも毎分ごとに新しいファイルをチェックするでスクリプトをスケジュールする必要がありますか?


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ではinotifywaitinotify-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 |
ルーゴ

2
@Lugouesそして今-fを使おうとすると、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 |この答えを試して編集することだけです。
ブルーノブロノスキー14

1
現在、それのための携帯用ツールもありますfswatch。私はそれを書いていませんが、それはオープンソースであり、私はそれを使用しています。

1
@Wender inotfiywaitは、トリガーされると1行に3つの情報を出力します。「読み取り」bashビルトインは、入力行を読み取り、3つの情報のそれぞれを変数に割り当てます。したがって、最初のピースは変数パスに、2番目はアクションに、3番目はファイルに割り当てられます。これらの変数に値を割り当てた後、それらを後で使用できるようになります(エコー行など)。詳細:tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
ティム

26

incron管理しやすいので、を好みます。基本的に、それは活用するサービスでinotifyあり、ファイル変更操作に基づいてアクションを実行するように構成をセットアップできます。

例:

<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

ファイル処理に時間がかかりすぎない場合は、新しいファイルを見逃さないでください。また、アクティビティの背景を確認することもできます...これは防弾ではありませんが、inotifyなどの外部ツールがなくてもいくつかの目的に役立ちます。


良いキャッチ。ファイル名のスペースをサポートするために少し改善しました。
マイケルサッキ

絶対に。それが道です。なぜその道を進んだのかはよくわかりませんが、-execを定期的に使用しています。
マイケルサッキ

リアルタイムではありません。リアルタイムは常に最高です
ファーハン

3
inotify利用できない場合の最適なソリューション。-type fファイルのみを除外するために追加します。それ以外の場合は、フォルダーも返されます。
シャオペン-ZenUML.com

うん- -f filenameオプションは素晴らしいです。したがって、残りの唯一の質問は、再起動時にこれを開始する方法です。これをソーラープラントで使用して、os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")このファイルを作成すると、マスターコンピューターespeakが低電圧を使用してアナウンスするようにします。それはすでに私に電子メールを送信しますが、私のシステムはすでに時間の一番上で時間を話すので、それはすべてを持っています。 askubuntu.com/questions/977613/...
SDsolar

19

watchスクリプトで使用できます

watch -n 0.1 ls <your_folder>

フォルダを監視し、0.1秒ごとにフォルダ内のすべてを一覧表示します

欠点

リアルタイムではないため、ファイルが0.1秒未満で作成および削除された場合、これは機能せず、watch最小0.1秒のみをサポートします。


それがまさに私が覚えようとしていたことです!どうもありがとう!!
ジョアベルセナ

9

ターゲットフォルダー(isempty単に便宜上の名前で呼ぶ)が空で、1つ以上のファイルがそこにドロップされるのを待っていると仮定しています。

次のコマンドを使用できます。

ls -1A isempty | wc -l

フォルダーがまだ空であるかどうかを確認するために、実際には新しいファイルがない場合(isemptyフォルダーがまだ空である場合)は0を返しますが、一方で、0より大きい値(実際は数値)を返します現在フォルダ内にあるファイルの)。

それは、ばかげたif / thenテストが残りの作業を行うことができるということです:

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

もちろん、do_something関数はisemptyフォルダー内のファイルを操作し、処理後にフォルダー自体から削除する必要があります。

crontabに次のような行を追加すると、1分に1回チェックが実行され、do_somethingもちろんフォルダーが空でない場合にアクションがトリガーされます。

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

このソリューションは、マウントされたリモートファイルシステムで機能します。inotify-tools開発者はfuseに取り組んでいます(または2014年半ばにいました)。
ロンド

3
lsスクリプトの作成には使用しないでください。find代わりに単純なグロビングを
andsens

6

新しいファイルを検出したい場合は、それらを処理し、最後にsystemd.pathを使用して進行中のファイルを削除します。このメソッドはinotifyに基づいています。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ファイルでサービス名を指定する必要はありません。

ダミーのファイルアクセスの監視に基づいています


4

entr

を使用することentrは、これを行う新しい方法です(クロスプラットフォームです)。Note 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を使用する必要があります(おそらくPythonも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

以下は、特定のディレクトリの監視を必要とするプロジェクトの1つにテストして組み込んだ、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.