web-dev-qa-db-ja.com

表示されたディレクトリ内のファイルを処理する

重複の可能性:
ディレクトリの内容が更新されたときにコマンドを実行する方法は?

毎分ディレクトリ内のファイルを検索する単純なetlプロセスを作成しようとしています。その場合は、それらをリモートシステムに(スクリプトを介して)ロードしてから削除します。

これを複雑にするもの:ロードには1分以上かかる場合があります。これを回避するために、すべてのファイルを一時的な処理ディレクトリに移動し、そこで操作して、そこから削除できると考えました。また、コマンドラインスクリプトを上手に利用するために、より洗練されたソリューションを探しています。以下に示すように、タスクを実行するための簡単なスクリプトを作成することから始めました。

#!/bin/bash

for i in ${find /home/me/input_files/ -name "*.xml"}; do
FILE=$i;
done;
BASENAME=`basename $FILE`
mv $FILE /tmp/processing/$BASENAME
myscript.sh /tmp/processing/$BASENAME other_inputs
rm /tmp/processing/$BASENAME

このスクリプトは、ファイルを処理ディレクトリからほぼ即座に削除し(重複処理の問題を停止します)、最後にそれ自体をクリーンアップし、その間にファイルを処理できるようにします。

しかし、これは結局U/Linuxです。かさばるスクリプトを維持する代わりに、物事を配管して移動することで、これらすべてを1行で実行できるはずだと感じています。

また、並行プロセスと並行して使用することはプラスになります。

補遺:ある種のFIFOキューが答えかもしれませんこれにも同様です。または、cronの代わりに他の種類のディレクトリウォッチャーを使用することもできます。私の小さなスクリプトよりもエレガントなすべての提案を受け付けています。唯一の問題は、「入力ディレクトリ」内のファイルが少し前に触れられることです。は実際に書き込まれるため、実際のファイルのみを処理するには、なんらかの!-size-0が必要になります。

4
J Jones

小さな処理スクリプトを書いて、GNU並列処理には並列を使用する必要があるように聞こえます:

http://www.gnu.org/software/parallel/man.html#example__gnu_parallel_as_dir_processor

だからこのようなもの:

inotifywait -q -m -r -e CLOSE_WRITE --format %w%f my_dir |
  parallel 'mv {} /tmp/processing/{/};myscript.sh /tmp/processing/{/} other_inputs; rm /tmp/processing/{/}'

詳細については、紹介ビデオをご覧ください: http://pi.dk/1

編集:

Myscript.shが長さ0のファイルを処理できる必要があります(たとえば、それらを無視します)。

touchを回避できる場合は、次のこともできます。

inotifywait -q -m -r -e CLOSE_WRITE --format %w%f my_dir |
  parallel myscript.sh {} other_inputs

GNU Parallelのインストールは次のように簡単です:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
4
Ole Tange

まず、スクリプトは1つのファイル(リストの最後)で動作します。また、ワンライナーが常に適切またはエレガントであるとは思いません。 Cronは舞台裏で多くのことを行い、失敗したことを確認できる必要があります。 cronを「頻繁に」実行すると問題が発生する可能性があります。これらのプロセスが数十回実行され、キュー内のファイルをすべて処理しようとしているため、システムの速度が低下する可能性があります。

これが私がすることです。

Dir="$HOME/input_files"   # never hardcode when you have variables
for filename in "$Dir"/*.xml; do
    # is the file non-empty AND is it still there, or may caught by another
    # process
    if [ -s "$filename" ]; then
        # move files locally will be faster than crossing filesystems to /tmp
        mkdir -p "$Dir/.processing"
        # temp name should use pid, just in case another input with the same name comes in
        tempname="$Dir/.processing/`basename $filename .xml`.$$"
        mv "$filename" "$tempname"
        # send stdout and stderr to a .output file
        myscript.sh "$tempname" other_inputs > "$tempname.output" 2>&1
        rc=$?
        if [ $rc -eq 0 ]; then
            rm "$tempname" "$tempname.output"
        else
            echo "Error processing $filename; rc=$rc" >&2
            echo "File in $tempname" >&2
        fi
    done

これにより、処理後にファイルが削除されるか、エラーが発生した場合、コマンドの出力を含む.processingディレクトリにファイルが保持されます。上記のコマンドは何も抑制しませんが、互いに干渉することなく複数のコマンドを実行できます。かなり効率的なワークキューを作成して拡張する方法については、他にも質問があります。

3
Arcege

inotify(7) インターフェイスを使用して、cronを介してポーリングするのではなく、着信ディレクトリを監視します。 inotify-toolsは、システムコールインターフェイスに対してコードを記述したくない場合にディレクトリを監視するために使用できるinotifywaitプログラムを提供します。

1
R Perrin