bash丢弃/编辑glob的一部分(当找不到部分glob时脚本失败)

时间:2015-04-04 03:04:02

标签: bash shell glob

我正在BASH编写一个脚本,它基本上就像一个简化的gmake&包装生成器。它只支持一个语言;这是设计的。我不打算发布此脚本,因为它仅供本地使用。

我大部分时间都正常运作。在更复杂的项目上,它处理好一切。做一个简单的测试程序时出现了问题。

该脚本构建«args»以使用基本参数来保证默认值。无论“模式”如何,脚本始终执行具有以下形式的行:

«compiler» «args» *.«ext»

鉴于支持的语言(Ada)有两个文件扩展名,以下的glob用于编译为“ext”:

*.{ads,adb}

当两个扩展存在时,正如大型项目所预期的那样,一切都很好。但是当$ PWD中只存在一个扩展时,脚本失败并且不会发生编译。

我对此感到困惑,因为存在“干净模式”,这只是:

rm *.{ali,o,so}

即使$ PWD中不存在某些列出的扩展名,也可以使用。

我可以调用编译器两次,首先传递一个扩展名,如果存在该文件的文件,然后同样传递另一个扩展名。然而,这会导致许多文件的编译发生两次,这显然效率低下。

我认为可以在$ PWD中存在扩展的脚本中尽早构建一个glob,然后将glob传递给编译器。但是,我完全不知道如何才能实现这一目标。有些人试图抱怨无法找到命令“*。{adb,ads}”。这真的让我感到惊讶,因为我基本上只是在做:

«compiler» «args» $FoundFiles

2 个答案:

答案 0 :(得分:1)

使用nullglob

shopt -s nullglob
compiler other_args *.{ads,adb}

解释

让我们使用一个包含.ads文件但没有.adb文件的目录:

$ echo *.{ads,adb}
1.ads *.adb

默认情况下,如果没有文件匹配glob,bash将返回glob本身,在本例中为*.adbnullglob选项会更改它,并且将省略不匹配的glob。因此:

$ shopt -s nullglob
$ echo *.{ads,adb}
1.ads

要将nullglob重置为off,请使用:

shopt -u nullglob

答案 1 :(得分:1)

支持扩展将*.{adb,ads}转换为两个字*.adb*.ads。然后,每个(独立地)全球扩展。如果glob-expansion失败,那么glob将不加修改地传递,而不是被删除。例如,如果您没有扩展名为ads的文件,则最终可能会尝试编译f1.adb f2.adb *.ads。由于最后一个不存在,编译器会抱怨。

rm *.{ali,o,so}会发生同样的事情,rm会抱怨并停止其中一个模式未经修改通过。但是如果命令真的是rm -f *.{ali,o,so},那么它将执行得很好,因为-f标志告诉rm忽略丢失的文件(等等)。

您可以通过设置nullglob shell选项(shopt -s nullglob)来修改bash对不匹配的globs的处理;设置该选项后,将从单词列表中删除不匹配的glob,而不是通过未修改的。>

但是,在这种特殊情况下,您也可以使用

compile *.ad[bs]

这是一个与支撑扩展的一对globs具有相同匹配的glob。如果它没有匹配任何东西,它也将通过未经修改的传递,但这意味着根本没有Ada文件,这应该触发错误消息。设置nullglob后,最终结果是不带参数调用编译器;这可能也会产生错误信息,但如果没有提供任何参数,某些实用程序将处理标准输入,在这种情况下你必须小心nullglob