我正在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
答案 0 :(得分:1)
使用nullglob
:
shopt -s nullglob
compiler other_args *.{ads,adb}
让我们使用一个包含.ads文件但没有.adb文件的目录:
$ echo *.{ads,adb}
1.ads *.adb
默认情况下,如果没有文件匹配glob,bash将返回glob本身,在本例中为*.adb
。 nullglob
选项会更改它,并且将省略不匹配的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
。