【问题标题】:Find files that are newer than another with similar name, but different extension查找名称相似但扩展名不同的文件
【发布时间】:2014-12-23 00:02:10
【问题描述】:

这是一个相当简单的问题,一直困扰着我。一点背景故事。我有一个装满脚本的文件夹。这些脚本获取数据文件*.dat 并在*.eps 中生成输出。我的脚本的扩展名是*.plt。我创建了一个运行该文件夹中所有*.plt 文件的单行shell 脚本。

#!/bin/sh
find . -name "*.plt" -exec {} \;

我只是想确保我将在文档中使用的所有*.pdf 图像都是最新的。一时间,单行脚本还不错。但是当文件数量超过 50 个时,运行需要一些时间。我很少更改数据文件,但经常更改*.plt 脚​​本。这些脚本的编写方式是,名为this_script_does_something.plt 的脚本将创建一个名为this_script_does_something.eps 的文件。

因此,这是我的问题。

  • 有没有办法编写一个精炼的 shell 脚本,只执行比类似的 *.eps 更新的 *.plt 文件?

我知道我可以在 Python 中做到这一点。但这似乎是作弊。我也知道我可以寻找更新的*.eps 并执行所有比这更新的*.plt。对于大多数实际情况,这将解决我的问题。我在输入问题时才意识到这个选项,所以谢谢 SX。但是,作为一个教学练习,为了解决我最初的疑问,我想搜索个别案例:比较每个 *.plt 与每个 *.eps 的修改时间,并且仅在它们比输出。可能吗?可以一行完成吗?

编辑:我忘了补充,*.plt 脚本也应该在没有同音字 *.eps 文件时执行,这通常意味着该脚本是新的并且尚未执行。

【问题讨论】:

    标签: shell find file-comparison


    【解决方案1】:

    我想我会使用:

    #!/bin/bash
    
    for plt in *.plt
    do
        eps=$(basename "$plt" .plt).eps
        if [ "$plt" -nt "$eps" ]
        then "$plt"
        fi
    done
    

    这使用 Bash/Korn shell 运算符 -nt 表示“比”(以及相反的 -ot 运算符表示“早于”)。我假设这些文件都在一个目录中,所以不需要递归搜索。如果不正确,请使用单独的:

    find . -type d -exec sh -c "cd {}; new-script.sh" \;
    

    (其中new-script.sh 是我刚刚展示的脚本)。或者使用 Bash 扩展 ** 运算符:

    for plt in *.plt **/*.plt
    

    您可能需要设置 Bash nullglob 选项:

    shopt -s nullglob
    

    当扩展不匹配任何文件时,这不会生成任何内容。


    .eps文件不存在时也生成:

    #!/bin/bash
    
    for plt in *.plt
    do
        eps=$(basename "$plt" .plt).eps
        if [ ! -f "$eps" ] || [ "$plt" -nt "$eps" ]
        then "$plt"
        fi
    done
    

    其中唯一不完全通用的 shell 功能是 -nt 运算符。如果您的/bin/sh 不支持它,请检查/bin/[ 命令——它可能——或者在shebang 行中使用Korn Shell 或Bash 而不是/bin/sh

    【讨论】:

    • 第一个脚本完全符合我的要求(是的,所有*.plt 都在同一个文件夹中)。我只会在 if 测试中添加一个额外的条件,以在 $eps 不存在时执行。我正在尝试复杂的单线,但这种方法更简单
    • 我建议先测试不存在的文件,然后再尝试将现有文件的时间与不存在的文件进行比较。否则,这工作正常。 -s 检查非空(但存在)文件; -f 不介意文件是否为空。
    • if [ ! -f "$eps" ] || [ "$plt" -nt "$eps" ] 之类的东西 我删除了我之前的评论,因为我无法编辑它。谢谢
    • 我的意思是:if [ ! -s "$eps" ] || [ "$plt" -nt "$eps" ]。命令从左到右进行评估并短路,因此如果$eps 文件不存在,则条件为真;如果它确实存在但比$plt 文件早(或相同年龄),则条件为真。对不存在的文件进行-nt 测试的可能性是合理的。 (我刚刚在有文件bombard.c 的目录中测试了if [ bombard.c -nt bombard.non-existent ]; then echo "OK"; else echo 'Oops!'; fi,它打印了OK[...继续...]
    • [...continuation...] 我尝试了一个名为 oldest 的文件,标记为 1969-12-31 16:01:00 和 1904-12-31 16:01: 00(在时区 UTC-08:00 — 又名美国/太平洋)和比较 if [ bombard.non-existent -nt oldest ]; then echo "OK"; else echo 'Oops!'; fi 打印“哎呀!”。因此,一个不存在的文件比任何文件都更旧;您可能不需要额外的测试。当然,您应该仔细检查一下。我在 Mac OS X 10.9.5 上使用 Bash (3.2.53…) 进行了测试。
    【解决方案2】:

    这个脚本应该做你所期望的:

    find . -name "*.eps" -exec sh -c \
         'plt=$(basename "$1" eps)plt; [ "$plt" -nt "$1" ] && $plt' sh {} \;
    

    如果有的话,它将递归到子目录中。如果你不想这样,而你使用 GNU find,一个简单的解决方法是运行:

    find . -maxdepth 1 -name "*.eps" -exec sh -c \
         'plt=$(basename "$1" eps)plt; [ "$plt" -nt "$1" ] && $plt' sh {} \;
    

    如果您不使用 GNU find,则可以改用该语法:

    find *.eps -type f -exec sh -c \
         'plt=$(basename "$1" eps)plt; [ "$plt" -nt "$1" ] && $plt' sh {} \;
    

    但如果您有大量与*.eps 模式匹配的文件,则后者可能会失败并出现“arg list too long”错误。任何基于for file in *.extension 循环的解决方案都会遇到同样的问题。

    还要注意 -nt 不是由 POSIX 指定的,因此根据您的系统,您可能需要明确说明要使用的 shell 而不是 sh(主流 shell,如 dashbashksh , ksh93zsh 支持 -nt)。例如,在 Solaris 10 上,您将使用:

    find . -name "*.eps" -exec ksh -c \
         'plt=$(basename "$1" eps)plt; [ "$plt" -nt "$1" ] && $plt' ksh {} \;
    

    编辑:

    如果.eps 文件不存在,脚本应该运行,因此该命令应该在.plt 文件上循环,例如:

    find *.plt -type f -exec bash -c \
         'eps=$(basename "$0" plt)eps;
         [ ! -f "$eps" -o "$0" -nt "$eps" ] && "$0"' "{}" \;
    

    【讨论】:

    • 酷。很近。我忘了在我的问题中提到脚本也应该在*.eps 文件不退出时运行(新创建的脚本)由于某种原因,我在最后一部分遇到问题:sh {}。我的脚本是gnuplot,第一行(解释器)是#!/usr/bin/gnuplot。我还应该添加 sh 吗?
    • 我已经删除了sh,虽然它不应该真的很痛。可能是{}gnuplot 窒息,我引用它以防万一。
    • 仍有问题。也许我急于要求单行命令。可能是我的 bashrc 上的东西正在杀死它。我的别名列表是从其他人那里继承的。我真的得把它清理干净。谢谢。我会接受另一个答案
    • 我上一个脚本出错了,我使用了一个不再存在的变量。现在应该解决这个问题。
    • 谢谢@jlliagre。我已经根据另一个答案的结构修改了我的脚本。我会尽快测试你的。再次感谢
    猜你喜欢
    • 1970-01-01
    • 2015-07-27
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多