ファイルがbashに存在するかどうかをテストするためのwhileループ


94

存在する場合にのみ、txtファイルに特定の変更を加えるシェルスクリプトを作成していますが、このテストループは機能しません。なぜでしょうか。ありがとうございました!

while [ ! -f /tmp/list.txt ] ;
do
      sleep 2
done

3
驚いたとは言えません。そのループは何も変更しようとしません。
Ignacio Vazquez-Abrams

セミコロンは冗長です。そのテストループはどのように機能しませんか?ファイル/tmp/list.txtが存在するまで、2秒間繰り返しスリープします。
ジョナサンレフラー

5
動作します-ファイルがスクリプトの外部で作成されると、ループが終了します。

1
実際、このループはファイルが存在するまで待機するだけであり、残りのスクリプトは変更を行います...:p
Zenet

1
その後、whileループが機能し、それは私だけです...すみません。
Zenet

回答:


145

「動作しない」と言ったとき、動作しないことをどうやって確認しますか?

次の行を追加して、ファイルが実際に存在するかどうかを調べてみてください。

while [ ! -f /tmp/list.txt ]
do
  sleep 2 # or less like 0.2
done
ls -l /tmp/list.txt

'echo $ SHELL'と入力して、Bash(または関連)シェルを使用していることを確認することもできます。CSHとTCSHは、このループに少し異なるセマンティクスを使用していると思います。


逆ファイルチェックを使用するのはなぜですか?代わりに[-f /tmp/list.txt]を使用しないでください。
ヴァレント2014年

2
@valenttないループが文字通り「NOTファイルが存在している間はスリープします」と言います..「NOT」を削除すると、ループは即座に壊れます
Kenyakorn Ketsombut '29

2
1行で:while [ ! -f /tmp/list.txt ]; do sleep 2; done; ls -l /tmp/list.txt
DrumM '13

55

Linuxを使用していて、inotify-toolsがインストールされている場合は、次のようにできます。

file=/tmp/list.txt
while [ ! -f "$file" ]
do
    inotifywait -qqt 2 -e create -e moved_to "$(dirname $file)"
done

これにより、「x」秒ごとにポーリングしながら、スリープによって生じる遅延が減少します。必要になると予想される場合は、さらにイベントを追加できます。


4
効率を上げるために+1。睡眠のプールは醜いです。inotifywaitを知らない人のために-inotify-toolsパッケージに含まれています。
のMichałŠrajer

7
これは非常に便利なツールです。なぜループなのかと思っている人にとっては、作成と待機の間で起こり得る競合状態に対処するためであり、inotifywaitは--excludeファイル名を除外する必要がありますが、ファイル名以外--includeすべて無視するわけではありません。上記のコマンドは、-qq代わりに引数を使用する必要が>&/dev/nullあります。
クレイグリンガー2013年

tは、--timeoutチェックの頻度ではなく、ですか?inotifywaitのポイントは、投票がないことです
Alex Dean

1
@AlexDeanタイムアウトは、競合状態を防ぐためのものです。ループはスリープ中に終了しないため、スリープでのポーリングは低速ですが、イベントを検出した場合、inotifywaitはタイムアウト前に終了します。
2015年

1
@AlexDeanはい。ただし、TOCTTOU競合状態を防ぐ必要があります。そうしinotifywaitないと、イベントのリスニングを開始する直前にファイルが作成された場合、無期限にハングする可能性があります。
2015

4

同じ問題がありました。大括弧の外側;

while ! [ -f /tmp/list.txt ];
do
    echo "#"
    sleep 1
done

また、ループ内にエコーを追加すると、ループに入っているかどうかがわかります。


2

私は同様の問題に遭遇し、それが私をここに導きました、それで私は同じことを経験する人のために私の解決策を残したいと思いました。

実行しcat /tmp/list.txtた場合、ファイルにコンテンツがすぐに配置されていることが確認されていても、ファイルが空であることがわかりました。それが期待どおりに機能するsleep 1;直前に私が置いた場合、判明しましたcat /tmp/list.txt。ファイルが作成されてから書き込まれるまでの時間、またはこれらの行に沿った何かの間に遅延があったに違いありません。

私の最後のコード:

while [ ! -f /tmp/list.txt ];
do
    sleep 1;
done;
sleep 1;
cat /tmp/list.txt;

これが誰かをイライラする30分救うのに役立つことを願っています!


1

@ zane-hooperと同様に、NFSでも同様の問題が発生しました。並列/分散ファイルシステムでは、1つのマシンでファイルを作成してから、それを「見る」別のマシンでのラグが非常に大きくなる可能性があるため、ファイルの作成後、whileループが終了するまで最大1分間待つことができます(そしてまた、既に削除されたファイルを「見る」ことによる後遺症もあります。

これにより、スクリプトが「機能しない」という幻想が生まれますが、実際には、ファイルシステムがボールを落としているのです。

これは私が理解するのにしばらくかかりました、それが誰かの時間を節約することを願っています。

PSこれはまた、不愉快な数の「古いファイルハンドラ」エラーを引き起こします。


0

bashとshの両方で動作します:

touch /tmp/testfile
sleep 10 && rm /tmp/testfile &
until ! [ -f /tmp/testfile ]
do
   echo "testfile still exist..."
   sleep 1
done
echo "now testfile is deleted.."

0

ここにタイムアウトのあるバージョンがあるので、しばらくするとループがエラーで終了します。

# After 60 seconds the loop will exit
timeout=60

while [ ! -f /tmp/list.txt ];
do
  # When the timeout is equal to zero, show an error and leave the loop.
  if [ "$timeout" == 0 ]; then
    echo "ERROR: Timeout while waiting for the file /tmp/list.txt."
    exit 1
  fi

  sleep 1

  # Decrease the timeout of one
  ((timeout--))
done

-3

このようにしてください

while true
do
  [ -f /tmp/list.txt ] && break
  sleep 2
done
ls -l /tmp/list.txt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.