6

私はシェルスクリプトを書いています。かなり定期的に何かがファイルに書き込まれ、その後、そのファイルを読み取るアプリケーションが実行されます。私たちの会社では、ネットワークの遅延が大きく異なることがわかりました。そのため、単純なsleep 2例では十分に堅牢ではありません.

次のような(構成可能な)タイムアウトループを書き込もうとしました:

waitLoop()
{
   local timeout=$1
   local test="$2"

   if ! $test
   then
      local counter=0
      while ! $test && [ $counter -lt $timeout ]
      do
         sleep 1
         ((counter++))
      done

      if ! $test
      then
         exit 1
      fi
   fi
}

これはtest="[ -e $somefilename ]". ただし、存在をテストするだけでは不十分です。特定の文字列がファイルに書き込まれたかどうかをテストする必要がある場合があります。を試し ましたが、うまくいきtest="grep -sq \"^sometext$\" $somefilename"ませんでした。誰かが理由を教えてもらえますか?

そのようなテストを実行するための、より詳細でない他のオプションはありますか?

4

8 に答える 8

1

次の方法でテスト変数を設定できます。

test=$(grep -sq "^sometext$" $somefilename)

あなたが機能していない理由grepは、引用符を引数に渡すのが本当に難しいからです。使用する必要がありますeval

if ! eval $test
于 2009-07-03T10:31:39.670 に答える
0

私はまったく同じ問題を抱えていました。OPに含めるタイムアウト待機と同様のアプローチを使用しました。ただし、ファイルサイズのチェックも含めました。ファイルが最後にチェックされてからサイズが大きくなった場合は、タイムアウトタイマーをリセットしました。私が書いているファイルは数ギガになる可能性があるので、NFSを介して書き込むには時間がかかります。

これはあなたの特定のケースではやり過ぎかもしれませんが、書き込みが完了した後、書き込みプロセスにファイルのハッシュを計算させました。私はmd5を使用しましたが、crc32のようなものでも機能します。このハッシュはライターから(複数の)リーダーにブロードキャストされ、リーダーはa)ファイルサイズの増加が停止し、b)ファイルの(新しく計算された)ハッシュがライターによって送信されたハッシュと一致するまで待機します。

于 2009-12-18T19:11:16.973 に答える
0

「if」でwaitLoopを使用する場合は、「exit」を「return」に変更して、スクリプトの残りの部分でエラー状況を処理できるようにすることができます(ユーザーへのメッセージすらありません)。スクリプトが終了する前に失敗したもの)。

もう1つの問題は、「$ test」を使用してコマンドを保持することです。つまり、実際に実行してもシェル拡張が行われず、評価するだけです。したがって、test = "grep \" foo \ "\" bar baz \ ""と言うと、7文字の名前bar bazを持つファイルで3文字の文字列fooを検索するのではなく、5文字の文字列を検索します。 9文字のファイル「barbaz」の「foo」。

したがって、シェルマジックが不要であると判断して、test ='grep -sq ^ sometext $ somefilename'を設定するか、次のようなものを使用してシェルに引用符を明示的に処理させることができます。

if /bin/sh -c "$test"
then
   ...
于 2009-07-03T07:29:50.370 に答える
0

シェルは述語を単語に分割していました。$@以下のコードのようにすべてを取得します。

#! /bin/bash

waitFor()
{
  local tries=$1
  shift
  local predicate="$@"

  while [ $tries -ge 1 ]; do
    (( tries-- ))

    if $predicate >/dev/null 2>&1; then
      return
    else
      [ $tries -gt 0 ] && sleep 1
    fi
  done

  exit 1
}

pred='[ -e /etc/passwd ]'
waitFor 5 $pred
echo "$pred satisfied"

rm -f /tmp/baz
(sleep 2; echo blahblah >>/tmp/baz) &
(sleep 4; echo hasfoo   >>/tmp/baz) &

pred='grep ^hasfoo /tmp/baz'
waitFor 5 $pred
echo "$pred satisfied"

出力:

$ ./ウェイトンゴ
[ -e /etc/passwd ] 満足
grep ^hasfoo /tmp/baz 満足

残念ながら、typescript はリアルタイムで見るほど面白くありません。

于 2009-12-22T14:47:50.380 に答える
0

テキスト ファイル内の文字列をチェックする方法は grepだと思います。

あなたの正確な問題は何ですか?

また、根本的な問題を取り除くために、NFS マウント パラメータを調整することもできます。同期も役立つ場合があります。NFS のドキュメントを参照してください。

于 2009-07-03T06:53:20.907 に答える
0

同様の問題がありますが、理由は異なります。SFTP サーバーに送信される s ファイルを読み込んでいます。スクリプトを実行しているマシンは SFTP サーバーではありません。

私が行ったことは、ファイルの cksum を実行するために cron で設定することです (ただし、スリープを伴うループも機能します)。古い cksum が現在の cksum と一致すると (ファイルが所定の時間変更されていない場合)、書き込みが完了したことがわかり、ファイルが転送されます。

安全のために、バックアップを作成する前にローカル ファイルを上書きすることはありません。リモート ファイルに一致する 2 つの cksum があり、その cksum がローカル ファイルと一致しない場合にのみ転送します。

コード例が必要な場合は、掘り下げることができると確信しています。

于 2009-12-21T21:49:24.223 に答える
-1

わかりました...これは少し奇抜です...

ファイルを制御できる場合: ここで「名前付きパイプ」を作成できる場合があります。そのため (書き込みプログラムの動作に応じて)、同期された方法でファイルを監視できます。

最も簡単に:

名前付きパイプを作成します。

mkfifo file.txt

同期された受信機をセットアップします。

while :
do
    process.sh < file.txt
end

テスト送信者を作成します。

echo "Hello There" > file.txt

「process.sh」はロジックの行き先です。これは、送信者が出力を書き込むまでブロックされます。理論的には、ライター プログラムを変更する必要はありません。

警告: 何らかの理由で受信者が実行されていない場合、送信者をブロックすることになる可能性があります!

ここでの要件に適合するかどうかはわかりませんが、検討する価値があるかもしれません。

または、同期を避けるために、「lsof」を試してください。

http://en.wikipedia.org/wiki/Lsof

他に何も書き込んでいないとき (つまり、書き込みプロセスが終了したとき) にのみファイルから読み取りたいと仮定すると、他にファイルハンドルがないかどうかを確認できますか?

于 2009-12-22T18:13:44.033 に答える