bash discard/edit 部分 glob(找不到部分 glob 时脚本失败)
bash discard/edit part of glob (script fails when part of glob not found)
我正在 BASH 中编写一个脚本,它基本上就像一个简化的 gmake 和包生成器。它只支持一种语言;这是设计使然。我不打算发布此脚本,因为它仅供本地使用。
我基本上都能正常工作。在更复杂的项目中,它处理得很好。做一个简单的测试程序时出现问题
该脚本使用基本参数将 «args» 构建为合理的默认值。无论 "mode",脚本始终执行具有以下形式的行:
«compiler» «args» *.«ext»
鉴于支持的语言 (Ada) 有两个文件扩展名,以下 glob 在编译时用作 «ext»:
*.{ads,adb}
当两个扩展都存在时,正如在大型项目中所期望的那样,一切都很好。但是当 $PWD 中只存在一个扩展时,脚本失败,并且不会进行编译。
我对此感到很困惑,因为 "clean mode" 存在,它只是:
rm *.{ali,o,so}
即使 $PWD 中不存在某些列出的扩展名,这仍然有效。
我可以调用编译器两次,首先传递一个扩展名(如果存在该扩展名的文件),然后同样传递另一个扩展名。然而,这会导致许多文件的编译发生两次,这是一个明显的低效率。
我认为可以在 $PWD 中存在哪些扩展的脚本中尽早构建一个 glob,然后将该 glob 传递给编译器。但是,我完全不知道如何做到这一点。一些尝试 bash 抱怨找不到命令“*.{adb,ads}”。这真的让我大吃一惊,因为我基本上只是在做:
«compiler» «args» $FoundFiles
使用nullglob
:
shopt -s nullglob
compiler other_args *.{ads,adb}
说明
让我们使用一个包含一个 .ads 文件但没有 .adb 文件的目录:
$ echo *.{ads,adb}
1.ads *.adb
默认情况下,如果没有文件与 glob 匹配,bash 将 return glob 本身,在本例中为 *.adb
。 nullglob
选项改变了这一点,没有匹配项的 glob 将被忽略。因此:
$ shopt -s nullglob
$ echo *.{ads,adb}
1.ads
要将 nullglob 重置为关闭,请使用:
shopt -u nullglob
大括号扩展将 *.{adb,ads}
变成两个单词,*.adb
和 *.ads
。然后,其中的每一个都(独立地)全局扩展。如果 glob 扩展失败,则 glob 将不加修改地传递,而不是被删除。例如,如果您没有扩展名为 ads
的文件,您可能最终会尝试编译 f1.adb f2.adb *.ads
。由于最后一个不存在,编译器会报错。
rm *.{ali,o,so}
和 rm
会发生完全相同的事情,如果其中一个模式未经修改就通过了,则 rm
会抱怨并停止。但是如果命令真的是 rm -f *.{ali,o,so}
,那么它将执行得很好,因为 -f
标志告诉 rm
忽略丢失的文件(除其他外)。
您可以通过设置 nullglob
shell 选项 (shopt -s nullglob
) 修改 bash 对不匹配 glob 的处理;设置该选项后,不匹配的 glob 将从单词列表中删除,而不是未经修改地传递。
但是,在这种特殊情况下,您也可以使用
compile *.ad[bs]
这是一个单一的 glob,与大括号扩展的 glob 对具有相同的匹配项。如果它不匹配任何内容,这也将不加修改地通过,但这意味着根本没有 Ada 文件,这应该会触发一条错误消息。设置 nullglob
后,最终结果将是不带参数调用编译器;这也可能会产生一条错误消息,但是如果某些实用程序没有提供任何参数,它们将处理标准输入,在这种情况下您必须小心 nullglob
。
我正在 BASH 中编写一个脚本,它基本上就像一个简化的 gmake 和包生成器。它只支持一种语言;这是设计使然。我不打算发布此脚本,因为它仅供本地使用。
我基本上都能正常工作。在更复杂的项目中,它处理得很好。做一个简单的测试程序时出现问题
该脚本使用基本参数将 «args» 构建为合理的默认值。无论 "mode",脚本始终执行具有以下形式的行:
«compiler» «args» *.«ext»
鉴于支持的语言 (Ada) 有两个文件扩展名,以下 glob 在编译时用作 «ext»:
*.{ads,adb}
当两个扩展都存在时,正如在大型项目中所期望的那样,一切都很好。但是当 $PWD 中只存在一个扩展时,脚本失败,并且不会进行编译。
我对此感到很困惑,因为 "clean mode" 存在,它只是:
rm *.{ali,o,so}
即使 $PWD 中不存在某些列出的扩展名,这仍然有效。
我可以调用编译器两次,首先传递一个扩展名(如果存在该扩展名的文件),然后同样传递另一个扩展名。然而,这会导致许多文件的编译发生两次,这是一个明显的低效率。
我认为可以在 $PWD 中存在哪些扩展的脚本中尽早构建一个 glob,然后将该 glob 传递给编译器。但是,我完全不知道如何做到这一点。一些尝试 bash 抱怨找不到命令“*.{adb,ads}”。这真的让我大吃一惊,因为我基本上只是在做:
«compiler» «args» $FoundFiles
使用nullglob
:
shopt -s nullglob
compiler other_args *.{ads,adb}
说明
让我们使用一个包含一个 .ads 文件但没有 .adb 文件的目录:
$ echo *.{ads,adb}
1.ads *.adb
默认情况下,如果没有文件与 glob 匹配,bash 将 return glob 本身,在本例中为 *.adb
。 nullglob
选项改变了这一点,没有匹配项的 glob 将被忽略。因此:
$ shopt -s nullglob
$ echo *.{ads,adb}
1.ads
要将 nullglob 重置为关闭,请使用:
shopt -u nullglob
大括号扩展将 *.{adb,ads}
变成两个单词,*.adb
和 *.ads
。然后,其中的每一个都(独立地)全局扩展。如果 glob 扩展失败,则 glob 将不加修改地传递,而不是被删除。例如,如果您没有扩展名为 ads
的文件,您可能最终会尝试编译 f1.adb f2.adb *.ads
。由于最后一个不存在,编译器会报错。
rm *.{ali,o,so}
和 rm
会发生完全相同的事情,如果其中一个模式未经修改就通过了,则 rm
会抱怨并停止。但是如果命令真的是 rm -f *.{ali,o,so}
,那么它将执行得很好,因为 -f
标志告诉 rm
忽略丢失的文件(除其他外)。
您可以通过设置 nullglob
shell 选项 (shopt -s nullglob
) 修改 bash 对不匹配 glob 的处理;设置该选项后,不匹配的 glob 将从单词列表中删除,而不是未经修改地传递。
但是,在这种特殊情况下,您也可以使用
compile *.ad[bs]
这是一个单一的 glob,与大括号扩展的 glob 对具有相同的匹配项。如果它不匹配任何内容,这也将不加修改地通过,但这意味着根本没有 Ada 文件,这应该会触发一条错误消息。设置 nullglob
后,最终结果将是不带参数调用编译器;这也可能会产生一条错误消息,但是如果某些实用程序没有提供任何参数,它们将处理标准输入,在这种情况下您必须小心 nullglob
。