0

这是一个相当简单的问题,一直困扰着我。一点背景故事。我有一个装满脚本的文件夹。这些脚本获取数据文件*.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 脚本,只执行*.plt比类似调用的文件更新的文件*.eps

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

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

4

2 回答 2

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

您可能需要设置 Bashnullglob选项:

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/[命令——它可能会——或者使用 Korn Shell 或 Bash 而不是/bin/sh在 shebang 行中。

于 2014-12-23T00:14:34.553 回答
1

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

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循环的解决方案都会遇到同样的问题。

另请注意,-ntPOSIX 未指定此内容,因此根据您的系统,您可能希望明确说明要使用的 shell,而不是sh(主流 shell,如, ,dashbashdo support )。例如,在 Solaris 10 上,您将使用:kshksh93zsh-nt

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"' "{}" \;
于 2014-12-23T00:14:45.883 回答