我有一个目录,除其他文件外,还包含 3 个命名管道:FIFO、FIFO1 和 FIFO11。如果我尝试类似的事情
grep mypattern *
在此目录中,grep 永远挂在命名管道上,因此我需要排除它们。不料,
grep --exclude='FIF*' mypattern *
没有解决问题; grep 仍然永远挂起。然而,
grep -r --exclude='FIF*' mypattern .
做解决挂起问题(尽管会产生搜索所有子目录的不良副作用)。
我做了一些测试,结果表明,grep --exclude ='FIF*' mypattern *
如果 FIFO 等是常规文件,而不是命名管道,则可以按预期工作。
问题:
- 如果它们是常规文件,为什么在这两种情况下都会
grep
跳过,并在递归情况下跳过命名管道,但在非递归情况下不跳过命名管道?--excludes
--excluded
- 是否有另一种方法来格式化排除,在所有情况下都会跳过这些文件?
- 有没有更好的方法来完成我所追求的目标? (编辑:我刚刚
--devices=skip
在 grep 中发现了该标志,所以这就是这部分的答案......但我仍然对问题的前两部分感到好奇)
答案1
看来grep
还是打开文件,即使正则表达式告诉它跳过它们:
$ ll
total 4.0K
p-w--w---- 1 user user 0 Feb 7 16:44 pip-fifo
--w--w---- 1 user user 4 Feb 7 16:44 pip-file
lrwxrwxrwx 1 user user 4 Feb 7 16:44 pip-link -> file
(注意:这些都没有读取权限。)
$ strace -e openat grep foo --exclude='pip*' pip-file pip-link pip-fifo
openat(AT_FDCWD, "pip-file", O_RDONLY|O_NOCTTY) = -1 EACCES (Permission denied)
grep: pip-file: Permission denied
openat(AT_FDCWD, "pip-link", O_RDONLY|O_NOCTTY) = -1 ENOENT (No such file or directory)
grep: pip-link: No such file or directory
openat(AT_FDCWD, "pip-fifo", O_RDONLY|O_NOCTTY) = -1 EACCES (Permission denied)
grep: pip-fifo: Permission denied
+++ exited with 2 +++
授予读取权限,如果排除它们,则打开后似乎不会尝试读取它们:
$ strace -e openat grep foo --exclude='pip*' pip-file pip-link pip-fifo
openat(AT_FDCWD, "pip-file", O_RDONLY|O_NOCTTY) = 3
openat(AT_FDCWD, "pip-link", O_RDONLY|O_NOCTTY) = -1 ENOENT (No such file or directory)
grep: pip-link: No such file or directory
openat(AT_FDCWD, "pip-fifo", O_RDONLY|O_NOCTTY^Cstrace: Process 31058 detached
<detached ...>
$ strace -e openat,read grep foo --exclude='pip*' pip-file
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\25\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\r\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260`\0\0\0\0\0\0"..., 832) = 832
openat(AT_FDCWD, "pip-file", O_RDONLY|O_NOCTTY) = 3
+++ exited with 1 +++
$ strace -e openat,read grep foo --exclude='pipe*' pip-file
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\25\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\r\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260`\0\0\0\0\0\0"..., 832) = 832
openat(AT_FDCWD, "pip-file", O_RDONLY|O_NOCTTY) = 3
read(3, "foo\n", 32768) = 4
foo
read(3, "", 32768) = 0
+++ exited with 0 +++
自从openat
未使用 调用O_NONBLOCK
,开头本身挂起,并且 grep 无法到达将其排除在读取之外的部分。
看了源码,我相信流程是这样的:
- 如果不递归,则调用
grep_command_line_arg
在每个文件上。 - 这叫
grepfile
如果不在标准输入上。 grepfile
来电grepdesc
后打开文件。grepdesc
检查排除该文件。
递归时:
grepdirent
检查排除文件在调用之前grepfile
,所以失败openat
永远不会发生。
答案2
为什么不和“find”结合起来呢?获取除了文件之外什么都没有的列表,然后 grep 进入其中:
find /path/to/dir -type f -exec grep pattern {} \;