如何跳过awk中的目录?

fed*_*qui 6 awk gawk dir

假设我有以下文件和目录结构:

$ tree
.
??? a
??? b
??? dir
    ??? c

1 directory, 3 files
Run Code Online (Sandbox Code Playgroud)

也就是说,两个文件ab一个dir dir,另一个文件c所在的位置.

我想用awk(GNU Awk 4.1.1,确切地)处理所有文件,所以我做这样的事情:

$ gawk '{print FILENAME; nextfile}' * */*
a
b
awk: cmd. line:1: warning: command line argument `dir' is a directory: skipped
dir/c
Run Code Online (Sandbox Code Playgroud)

一切都很好,但*也扩展到目录dirawk尝试处理它.

所以我想知道:有没有本地方法awk可以检查给定元素是否是一个文件,如果是,跳过它?也就是说,不用system()它.

我通过systemBEGINFILE中调用外部来使它工作:

$ gawk 'BEGINFILE{print FILENAME; if (system(" [ ! -d " FILENAME " ]")) {print FILENAME, "is a dir, skipping"; nextfile}} ENDFILE{print FILENAME, FNR}' * */*
a
a 10
a.wk
a.wk 3
b
b 10
dir
dir is a dir, skipping
dir/c
dir/c 10
Run Code Online (Sandbox Code Playgroud)

还要注意if (system(" [ ! -d " FILENAME " ]")) {print FILENAME, "is a dir, skipping"; nextfile}直观地解决这个问题的事实:它应该在为true时返回1,但它返回退出代码.

我在A.5中读到gawk中的扩展而不是POSIX中的awk:

然后链接页面说:

4.11命令行上的目录

根据POSIX标准,awk命令行上命名的文件必须是文本文件; 如果他们不是,这是一个致命的错误.大多数版本的awk将命令行上的目录视为致命错误.

默认情况下,gawk会在命令行上为目录生成警告,否则会忽略它.这使得使用awk程序更容易使用shell通配符:

$ gawk -f whizprog.awk *        Directories could kill this program
Run Code Online (Sandbox Code Playgroud)

如果给出了--posix或--traditional选项中的任何一个,那么gawk将恢复为将命令行上的目录视为致命错误.

有关将目录视为来自awk程序的可用数据的方法,请参阅Extension Sample Readdir.

事实上情况就是这样:与之前相同的命令--posix失败:

$ gawk --posix 'BEGINFILE{print FILENAME; if (system(" [ ! -d " FILENAME " ]")) {print FILENAME, "is a dir, skipping"; nextfile}} ENDFILE{print FILENAME, NR}' * */*
gawk: cmd. line:1: fatal: cannot open file `dir' for reading (Is a directory)
Run Code Online (Sandbox Code Playgroud)

我检查了16.7.6 Reading Directories上面链接的部分,他们谈到readdir:

readdir扩展为目录添加了一个输入解析器.用法如下:

@load"readdir"

但我不确定如何调用它以及如何从命令行使用它.

hek*_*mgl 5

我只是避免将目录传递给awk,因为即使POSIX说所有文件名都必须是文本文件.

您可以使用find遍历目录:

find PATH -type f -exec awk 'program' {} +
Run Code Online (Sandbox Code Playgroud)


Ed *_*ton 3

如果您想保护您的脚本免遭其他人错误地将目录(或任何其他不可读的文本文件)传递给它,您可以这样做:

$ ls -F tmp
bar  dir/  foo

$ cat tmp/foo
line 1

$ cat tmp/bar
line 1
line 2

$ cat tmp/dir
cat: tmp/dir: Is a directory

$ cat tst.awk
BEGIN {
    for (i=1;i<ARGC;i++) {
        if ( (getline line < ARGV[i]) <= 0 ) {
            print "Skipping:", ARGV[i], ERRNO
            delete ARGV[i]
        }
        close(ARGV[i])
    }
}
{ print FILENAME, $0 }

$ awk -f tst.awk tmp/*
Skipping: tmp/dir Is a directory
tmp/bar line 1
tmp/bar line 2
tmp/foo line 1

$ awk --posix -f tst.awk tmp/*
Skipping: tmp/dir
tmp/bar line 1
tmp/bar line 2
tmp/foo line 1
Run Code Online (Sandbox Code Playgroud)

如果/当尝试从文件中检索记录失败时(例如,不可读的文件或文件不存在或文件是目录),Per POSIX返回getline,您只需要 GNU awk 来通过值告诉您是哪一个失败如果你在意。-1ERRNO

  • 不错!因此目录上的 getline 不会直接失败,而是可以处理。 (2认同)