glob表达式是否需要缓存?如何强制刷新?

时间:2017-05-18 20:10:30

标签: bash shell

我的脚本在无限循环中从Web服务器下载文件。我的脚本调用wget来获取最新的文件(我之前没有得过的文件),然后需要处理每个新文件。问题是在运行wget之后,文件已经正确下载(基于单独窗口中的ls),但有时我的脚本(特别是开始for curFile in的行)看到它们,有时它没有,这让我觉得它有时会看到一个过时的缓存。

while [ 5 -lt 10 ]; do
timestamp=(date +%s)
wget -mbr -l0 --no-use-server-timestamps --user=username --password=password ftp://ftp.mysite.com/public_ftp/incoming/*.txt
for curFile in ftp.mysite.com/public_ftp/incoming/*.txt; do
    curFileMtime=$(stat -c %W "$curFile")
    if((curFileMtime > timestamp)); then
        echo "$curFile"
        cp "$curFile" CommLink/MDLFile
        cd CommLink
        SendMDLGetTab
        cd ..
    fi
done
sleep 120
done 

通过循环的前几次这似乎工作正常,然后它变得零星(有时它看到新文件,有时它没有)。我已经做了很多谷歌搜索,并发现bash确实缓存了用于运行可执行文件的路径名(所以有时它会尝试执行不在那里的东西,如果最近删除了可执行文件)但我还没有找到任何东西在缓存非可执行文件名时,这会导致它看不到那些东西。有任何想法吗?如果是缓存问题,我怎么强迫它不要查看缓存?

1 个答案:

答案 0 :(得分:0)

作为最直接的问题 - -b的{​​{1}}参数告诉它在后台运行。因此,设置此标志后,第一个后续命令将在wget仍在运行时发生。

除此之外:全局表达式的结果 - 例如wget - 不会被shell缓存然而,这个glob只在每个循环中被评估一次:如果一个新的文本文件在该循环的开始时不存在,它将不会被拾取直到下一次迭代。

但是,问题中的代码用于排除ftp.mysite.com/public_ftp/incoming/*.txt运行之前已存在的文件的机制很容易出现竞争条件。我会建议以下内容:

wget

一些更好的观点:

  • 上面的代码将时间戳与 MDLFile 的当前副本进行比较,而不是循环当前迭代的开头。如果在while IFS= read -r -d '' filename; do [[ "$filename" -nt CommLink/MDLFile ]] || continue # retest in case MDLFile has changed cp -- "$filename" CommLink/MDLFile && { touch -r "$filename" CommLink/MDLFile # copy mtime to destination (cd CommLink && exec SendMDLGetTab) # scope cd to subshell } done < <(find ftp.mysite.com/public_ftp/incoming/ \ -name '*.txt' \ -newer CommLink/MDLFile \ -print0) 之后但在wget之前中断此脚本的先前调用,则确保处理更新方面更加强大。
  • 使用cp可确保MDLFile的新副本保留原始文件的mtime。 (有人可以用touch -r替换cp以硬链接inode以获得相同的效果而没有任何竞争条件,并且只在磁盘上存储一次MDLFile,如果副作用可以接受的话。)
  • 上面的代码只执行要在子目录中运行的操作,如果该子目录中的ln -f成功,则cd的范围通过执行要在子shell中的单独目录中执行的操作。 (运行外部命令时,使用cd会抵消此子shell的成本,其最终目的是触发)。
  • 使用NUL分隔的流(如exec中所示)可确保正确处理所有可能的名称(包括带有文字换行符的名称)。
  • 时间戳是否以整数级分辨率存储或更高,因文件系统而异;但是,bash只支持整数数学。以上 - 其中没有由shell执行数字比较 - 因此更加健壮。