web-dev-qa-db-ja.com

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

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

141
ihatetoregister

例として、inotifywaitの使用を検討する必要があります。

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

Ubuntuでは、inotifywaitinotify-toolsパッケージによって提供されます。バージョン3.13以降(Ubuntu 12.04で現在)inotifywaitには、-fオプションなしのファイル名が含まれます。古いバージョンは強制する必要があるかもしれません。注意すべき重要なことは、inotifywait-eオプションがイベントフィルタリングを行うための最良の方法であることです。また、readコマンドを使用して、位置出力を複数の変数に割り当て、使用または無視するように選択できます。出力を前処理するためにgrep/sed/awkを使用する必要はありません。

168
enzotib

私はこれを調理しましたが、チェックとチェックの間にファイルが見つからないというわずかな可能性を除いて、大きな問題はありません。

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

ファイルの処理にそれほど時間がかからない場合は、新しいファイルを見逃してはなりません。また、活動の背景を説明することもできます...これは完全な証拠ではありませんが、inotifyのような外部ツールなしでいくつかの目的を果たします。

28
Michael Sacchi

管理が簡単なため、 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/

27
rynop

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

watch -n 0.1 ls <your_folder>

フォルダを監視し、0.1秒ごとにフォルダ内のすべてをリストします

欠点

リアルタイムではないので、ファイルが作成されて0.1秒未満で削除された場合、これは機能しません。watchは最小0.1秒しかサポートしません。

26
GypsyCosmonaut

ターゲットフォルダー(便宜上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回チェックが実行され、もちろんフォルダーが空でない場合はdo_somethingアクションがトリガーされます。

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

entr

entrを使用することが、これを行う新しい方法です(クロスプラットフォームです)。注entrはポーリングを使用しないため、他の多くの方法よりもはるかに優れています。

kqueue(2)またはinotify(7)を使用して、ポーリングを回避します。 entrは、迅速なフィードバックと自動テストを自然で完全に通常のものにするために作成されました。

BSDではpledge(2)を使用します

あなたはそれをインストールすることができます

apt-get install entr
dnf install entr
brew 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の制御は子プロセスに転送されません。
8
Evan Carroll

新しいファイルを検出したい場合は、それらを処理し、最後に処理されたファイルを削除します 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ファイルでサービス名を指定する必要はありません。

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

7
Dawid Wolski

Bashはこれを簡単に行うことはできません。基本的に、フォルダー内のすべてのファイルのリストを取得し、定期的に新しいリストを取得してそれらを比較し、変更点を確認する必要があります。

あなたが探しているものはinotifyと呼ばれています。 Linuxカーネルに組み込まれており、基本的にそこに座って何かが起こるのを待って、その時点でinotifyが戻ってきて「foobarという新しいファイルがあります」と言うことができます。

あなたが望むことを達成するには、Perlのようなものに切り替えてLinux :: Inotify2を使用する必要があります(Pythonはおそらくinotifyもサポートしていますが、私はPerlの人です)。

2
Patrick

これはcygwinとLinuxで動作します。ファイルを書き込む以前のソリューションのいくつかは、ディスクをスラッシュさせます。このsciptにはその問題はありません。

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
user1186515

以下は stackoverflow の例の要約版で、特定のディレクトリの監視を必要とするプロジェクトの1つにテストして組み込んだものです。

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マウントポイントにあるファイルまたはディレクトリを自動的に復号化する script へのリンクは次のとおりです。前述のプロジェクト。

0
S0AndS0