测试用例:(使用非 root 用户,因为 root 会忽略 000 权限...)
#in a clean directory:
[ -f file_1 ] && chmod 600 file_? # for repeat tests...
for i in file_1 file_2 file_3; do
printf 'A\nB\n' > "$i"
# we need at least 1 char : awk/gawk silently skips empty files...
done
chmod 000 file_2
awk '(FNR==1) { print FILENAME }' file_?
# tried with : regular (old unixes) awk on AIX. and gawk on Linux.
# the fatal "permission denied" on file_2 stops [g]awk.
有没有办法捕获该致命错误并继续处理下一个文件?
(否则我觉得这很令人担忧:对一堆文件使用 awk 并不能保证处理所有文件,因为如果其中任何一个文件不可读,它将致命地退出)
如果可以的话请:回答
- 对于常规 awk,
- 和傻瓜
- 还有其他相关的 awk 版本吗?(诺克?等)
与 GAWK 一起:
如果文件成功打开,则
BEGINFILE
块中为空,可用于跳到下一个并避免因错误而退出。ERRNO
nextfile
我认为 AWK 的其他实现不支持这一点。
可移植的是,您可以迭代所有参数,检查它们是否指向不可读的文件,如果是,则在 AWK 开始处理它们之前将它们从参数中删除;GAWK 手册有一个示例实现。然而,这是很危险的,因为使用此循环检查的文件可能在 AWK 开始处理它之前变得不可读(反之亦然)。
正如 @StephenKitt 和 @ilkkachu 已经指出的那样,gawk 手册包含一些代码,这些代码将从
ARGV[]
该BEGIN
部分中删除不可读的文件,但在测试文件和 awk 实际尝试读取其内容之间存在竞争条件,这可能会很多如果前面的文件很大,请稍后再执行。如果您有 gawk 或 gawk 手册中的脚本,我会使用 @StephenKitt 的答案中的脚本,否则除非您确实认为可能存在竞争条件问题,因为 gawk 手册脚本更清晰、更简短、更简单、更高效等。比下面的要好,不需要临时文件和全局变量,但对于那些担心竞争条件的人来说 - 这是一个更复杂的脚本,可以在任何 awk 中工作,并依赖于创建一个临时文件以在尝试之前立即打开打开任何真实文件,然后测试即将到来的真实文件是否可读。
如果您的 awk 支持多个
-f
参数(例如POSIX的要求)或同时执行多个脚本的任何其他方式(例如 GNU awk 有@include
),那么您可以使用该方法将上述内容与您的实际脚本一起包含(否则复制/粘贴上面到同一个文件中),例如假设您有一个如下脚本:和文件如:
然后使用任何 POSIX awk(以及大多数(如果不是全部)其他),您可以执行以下操作:
上面的大部分工作都是在
BEGIN
第一个输入文件打开之前调用一次,以确保ARGV[]
每个实际输入文件之前都存在一个可读的临时文件,然后chkTmp()
为每一行输入调用,但仅在它是第一个输入时才执行某些操作(也是唯一)临时文件的行,并且尝试打开ARGV[]
. 然后END
只需删除临时文件。因此,真正的额外开销是对每个输入行的调用chkTmp()
和测试FNR==1
。我正在创建一个临时文件而不是使用现有文件,因为没有任何文件可以保证在所有 Unix 机器上都存在,即使有,它也必须正好 1 行长,以避免增加额外的开销
chkTmp()
必须读取该文件的每一行,因为并非所有 awks 都支持nextfile
(或者我们可以调用它而不是next
insidechkTmp()
)。