While循环以测试bash中是否存在文件


94

我正在开发一个shell脚本,该脚本仅在txt文件确实存在的情况下对其进行某些更改,但是此测试循环不起作用,我想知道为什么吗?谢谢!

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

3
我不能说我很惊讶;该循环不会尝试更改任何内容。
伊格纳西奥·巴斯克斯

分号是多余的。该测试循环以哪种方式不起作用?它将反复睡眠2秒钟,直到文件/tmp/list.txt存在。
乔纳森·勒夫勒

5
对我有用-在脚本之外创建文件时,循环终止。

1
实际上,此循环仅用于等待文件存在,我的脚本其余部分进行更改...:p
Zenet 2010年

1
然后while循环起作用了,只有我...对不起。
Zenet 2010年

Answers:


145

当您说“无效”时,您怎么知道它无效?

您可以尝试通过添加以下内容来确定文件是否实际存在:

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

您还可以通过键入“ echo $ SHELL”来确保您正在使用Bash(或相关)shell。我认为CSH和TCSH在此循环中使用的语义稍有不同。


为什么要使用倒排文件检查?不应同时使用[-f /tmp/list.txt]吗?
2014年

2
@valentt没有he回叫声从字面上说“当没有文件存在时请入睡” ..如果您删除“ NOT”,则回
叫声

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

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软件包中。
2011年

7
那是一个非常方便的工具。对于任何想知道为什么循环的人来说,它都是为了处理创建和等待之间的竞争情况,因为inotifywait必须--exclude过滤掉文件名,而不是--include忽略文件名以外的所有内容。上面的命令应该使用-qq参数,而不是>&/dev/null
克雷格·林格

t是--timeout,不是检查频率,不是吗?inotifywait的要点是没有轮询
Alex Dean

1
@AlexDean超时是为了防止出现竞争情况。睡眠轮询很慢,因为循环不会在睡眠期间退出,但是inotifywait如果看到事件,将在超时之前退出。
yingted 2015年

1
@AlexDean是的,但是有必要防止TOCTTOU竞赛情况。否则,inotifywait如果在开始监听事件之前创建了文件,则可能会无限期挂起。
yingted 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;

希望这可以帮助您节省一个令人沮丧的半小时!


1

像@ zane-hooper一样,我在NFS上也遇到了类似的问题。在并行/分布式文件系统上,您在一台计算机上创建文件而另一台计算机“看到”该文件之间的时延可能非常大,因此,我可以在创建文件后等待一整分钟,然后再退出while循环(和还有一个“看到”已经删除的文件的后果)。

产生了脚本“不起作用”的错觉,而实际上是文件系统在起作用

这花了我一段时间才能弄清楚,希望它可以节省一些时间。

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.