grep --exclude 选项并不总是跳过命名管道

grep --exclude 选项并不总是跳过命名管道

我有一个目录,除其他文件外,还包含 3 个命名管道:FIFO、FIFO1 和 FIFO11。如果我尝试类似的事情

grep mypattern *

在此目录中,grep 永远挂在命名管道上,因此我需要排除它们。不料,

grep --exclude='FIF*' mypattern *

没有解决问题; grep 仍然永远挂起。然而,

grep -r --exclude='FIF*' mypattern .

解决挂起问题(尽管会产生搜索所有子目录的不良副作用)。

我做了一些测试,结果表明,grep --exclude ='FIF*' mypattern *如果 FIFO 等是常规文件,而不是命名管道,则可以按预期工作。

问题:

  1. 如果它们是常规文件,为什么在这两种情况下都会grep跳过,并在递归情况下跳过命名管道,但在非递归情况下不跳过命名管道?--excludes--excluded
  2. 是否有另一种方法来格式化排除,在所有情况下都会跳过这些文件?
  3. 有没有更好的方法来完成我所追求的目标? (编辑:我刚刚
    --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 无法到达将其排除在读取之外的部分。

看了源码,我相信流程是这样的:

  1. 如果不递归,则调用grep_command_line_arg在每个文件上。
  2. 这叫grepfile如果不在标准输入上。
  3. grepfile来电grepdesc 打开文件。
  4. grepdesc检查排除该文件

递归时:

  1. grepdirent 检查排除文件在调用之前grepfile,所以失败openat永远不会发生。

答案2

为什么不和“find”结合起来呢?获取除了文件之外什么都没有的列表,然后 grep 进入其中:

find /path/to/dir -type f -exec grep pattern {} \;

相关内容