【问题标题】:Why is this bash while loop infinite?为什么这个 bash while 循环是无限的?
【发布时间】:2014-06-22 14:54:32
【问题描述】:

这是我第一次制作 bash 脚本...

我正在尝试制作一个 bash 脚本,该脚本将删除目录中最旧的文件,直到所述目录低于特定大小。一旦目录小于 10000 字节,我希望 while 查找停止。 10000 仅用于测试;以后会增加的。

du 和 cut 将目录大小(以字节为单位)放入名为 check 的变量中 当文件大小大于 10000 字节时,应该运行 while 外观。 每次迭代都会删除目录中最旧的文件。

当我运行这个脚本时,最旧的文件被删除了,但即使 $check 小于 10000 也会无限重复。为什么这个脚本会无限运行?

check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)

while [ $check -gt 10000 ]
check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
do
cd /home/chris/Dropbox/VideoMonitor
ls /home/chris/Dropbox/VideoMonitor -1tr | head -1 | xargs rm
done

这是脚本从目录中删除所有文件后得到的输出。

rm: missing operand
Try 'rm --help' for more information.

这会一遍又一遍地运行

【问题讨论】:

    标签: bash while-loop infinite


    【解决方案1】:

    你的脚本有两个错误:

    第一个错误是损坏的while 子句,它应该是

    while condition; do
        commands
    done
    

    while condition
    do
        commands
    done
    

    condition 可能是一个返回零或非零的测试表达式,正如您正确写道:

    [ $check -gt 10000 ]
    

    线

    check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
    

    do 定位错误之前。我打赌你想把它放在do 之后再次获得价值。

    第二个错误是您使用xargs。由于您要传递给xargs 的文件列表可能为空,因此您需要添加开关--no-run-if-empty 来修复rm: missing operand 错误。

    为避免两次写入 check 行,您可以编写一个 while-true 循环并检查内部条件并跳出循环,因为 bash 没有头部控制的 while 循环。

    while [ true ]; do
       check = ...
       if [ $check -le 10000 ]; then
           break
       fi
    
       ...
    done
    

    其他建议

    • 您不需要在循环中每次都执行cd,在此之前执行此操作
    • 如果您想删除超过特定时间的文件而不是检查目录大小,您可以使用find -mtime +N(查找修改日期早于 (+) 的文件,而不是 N 天)
    • 有时bash的pushdpopdcd更方便,因为cd在脚本执行后改变了目录,你需要记住之前的目录为cd back. Withpushdyou tell bash to do set the current directory wherepopd`你回到上一个目录。在directory stack functions

    【讨论】:

    • 环境更改,包括更改目录,不会传播回父 shell。因此,如果他的脚本执行“cd”命令,当脚本退出时,您的 shell 仍将处于执行脚本时的位置。
    • 感谢您和其他所有人提供信息丰富的答案
    【解决方案2】:

    我想do 必须check 的重新分配之前。否则它实际上不是循环体的一部分。此外,可能应该在主体执行之后(以及在循环条件的下一次测试之前) 完成分配:

    check=$(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
    
    while [ $check -gt 10000 ]
    do
    cd /home/chris/Dropbox/VideoMonitor
    ls /home/chris/Dropbox/VideoMonitor -1tr | head -1 | xargs rm
    check=$(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
    done
    

    我还删除了 = 周围的空格,以使您的 check=... 行实际上是赋值语句。

    【讨论】:

    • 几乎。删除后只需将检查移到循环内更新即可,否则删除一个文件太多。
    • 请注意,第一行 check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)= 周围的空格运行命令 check 与运算符 = 和命令替换的结果!
    【解决方案3】:

    您的 while 循环子句中有两个命令,[ $check -gt 10000 ]check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)(这是一个错误的命令,而不是一个分配,因为 =-sign 周围有空格)。后一个命令是唯一确定 while 循环是否终止的命令。如果它的返回码总是 0 那么 while 循环永远不会结束..

    如果没有文件,则rm 命令没有操作数,因此错误消息..

    【讨论】:

      【解决方案4】:

      不要在作业中的 = 周围放置空格

      check=$(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
      
      while [ $check -gt 10000 ]
      check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)
      do
      cd /home/chris/Dropbox/VideoMonitor
      ls /home/chris/Dropbox/VideoMonitor -1tr | head -1 | xargs rm
      done
      

      【讨论】:

        猜你喜欢
        • 2016-07-14
        • 2012-05-02
        • 2018-03-17
        • 2011-11-15
        • 2012-11-01
        • 2016-07-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多