如何在目录中非递归地对所有文件使用grep?


34

我想在目录中的所有文件中搜索文本字符串(而不是其子目录;我知道该-r选项可以这样做,但这不是我想要的)。

  1. 跑步

    grep "string" /path/to/dir
    

    我已经阅读了,应该能够做到这一点,但它给了我错误:

    grep:dir:是目录

  2. 接下来,我尝试grep在多个文件上运行。

    grep "string" .bashrc .bash_aliases 完美地工作。

    grep "string" .bash* 也按预期工作。

    grep "string" * 给我错误:

    grep: data: Is a directory
    grep: Desktop: Is a directory
    grep: Documents: Is a directory
    grep: Downloads: Is a directory
    ...
    

只打印错误,我没有找到匹配的行。我尝试使用该-s选项,但无济于事。

所以,我的问题是:

  1. 为什么grep我应该可以在(1)中无法在目录上使用?我已经在互联网上看到很多例子。
    编辑:当我说“在目录上使用grep”时,我的意思是“搜索该目录中除其子目录外的所有文件”。我相信这是grep在您将目录传递给文件而不是文件时所做的。我不正确吗?

  2. 请给我一个解释,它的工作原理grep将解释(2)中命令的行为。
    编辑:让我更具体。为什么使用通配符指定要搜索的多个文件.bash*,而不使用*甚至搜索./*

  3. 如何使用来搜索目录(而不是其子目录)中的所有文件grep


另外,您还需要依靠Shell扩展通配符,例如*,称为通配符。globbing不包括以点(例如.bashrc标准)开头的文件名。您可以设置外壳程序选项,使其包含这些文件,但是如果您不知道自己在做什么,则可能会陷入混乱。可以在这里找到了解球形的好指南mywiki.wooledge.org/glob
Arronical '16

我不知道为什么,但是我总是对隐藏文件进行遍历,并且一直有效。我没有更改任何设置或其他内容。正如我在(2)中指出的那样,它也适用grep "string" .bash*
约翰·雷德

抱歉,我的上一个示例不正确。您也可以在隐藏文件中搜索,并取消显示“是目录”,因为Linux从技术上将目录视为另一种文件类型。该命令将是: grep "string" * .* 2>/dev/nullgrep -s "string" * .*
Terrance

Answers:


40

在Bash中,一个glob不会扩展为隐藏文件,因此,如果要搜索目录中的所有文件,则需要指定隐藏文件.*和non-hidden *

为了避免出现“是目录”错误,可以使用-d skip,但是在我的系统上也会出现错误grep: .gvfs: Permission denied,因此我建议使用-s,它会隐藏所有错误消息。

因此,您要查找的命令是:

grep -s "string" * .*

如果要在另一个目录中搜索文件:

grep -s "string" /path/to/dir/{*,.*}

另一个选择是使用dotglobshell选项,这将使一个glob包含隐藏文件。

shopt -s dotglob
grep -s "string" *

对于另一个目录中的文件:

grep -s "string" /path/to/dir/*

†有人提到我不应该收到此错误。他们可能是对的-我读了一些书,但本人却无法做到。


是否有任何理由之间的空间*.*
Hashim

2
@Hashim比较的输出echo * .*echo *.*在您的主目录中运行,两者之间的区别应该很明显。否则LMK,我会解释。
wjandrea

有趣的是,它echo *显示了非隐藏的文件和文件夹,echo *.*显示了非隐藏的文件,echo .*显示了所有文件,并echo * .*显示了所有文件和目录。但是,为什么在后一种情况下两者之间留有间隔呢?我觉得很乱。有没有办法将两者结合起来以获得相同的结果?否则,是否存在语法解释,说明为什么此处需要将两者分开,还是* .*例外情况?
Hashim

1
@Hashim我不确定您是如何得出这些结论的,所以让我解释一下。首先,目录是这种情况下的文件。以globs *表示所有非隐藏文件(即,文件名以点开头);.*代表所有隐藏文件(即文件名,并先从一个点); 并*.*代表所有包含点的非隐藏文件。在中echo * .*,两个glob必须分开,因为它们是不同的glob:一个为非隐藏,一个为隐藏。尽管正如我在回答中所写,您可以*通过打开dotglobshell选项使包含隐藏文件成为可能。
wjandrea

1
*.*在Windows(DOS)上,使用它作为列出所有文件的一种方式很普遍,但是在* nix上将仅包含其中带有点的文件,因此在* nix上没有意义。相反,您用于*列出除隐藏文件以外的所有文件,并.*列出隐藏文件。
thomasrutter

10

您需要-d skip添加选项。

  1. Grep正在文件内搜索。如您所说,您可以递归搜索,如果要搜索目录中的文件。

  2. 默认情况下,grep将读取所有文件,并检测目录。由于默认情况下您尚未定义使用-d选项处理目录的方式,因此会产生错误输出。

  3. 仅在父目录中搜索将是`grep -d skip“ string” ./*


有关grep的更多信息,请参见man grep
匿名

(a)请查看编辑。(b)使用-d skip不起作用;它基本上与-s; 另外,请参见编辑。(c)不,grep -d skip "string" ./*也不起作用。
约翰·雷德

7

老计时器可能会这样做:

find . -type f -print0 | xargs -0 grep "string"

3
为什么不find . -type f -exec grep string {} +呢?
wchargin '16

5
你也要-maxdepth 1
wchargin '16

@wchargin:如果我只想要一个文件时,如果想要输出中的文件名find . -type f -maxdepth 1 -exec grep string /dev/null {} +
Gregory Nisbet

1
@GregoryNisbet:只需传递-H给grep。
wchargin

2

改写-您想在一级子目录中grep文件,但不希望通过所有子子目录递归?

grep forthis  *  */*

或者如果您不希望当前目录中的文件

grep forthis  */*

请注意,这将找不到以点开头的目录。

grep forthis  .*/*    */*   

应该做那个工作。

该命令还提供了-maxdepth-mindepth限制参数find


grep forthis */*既不能在当前目录中搜索文件,也不能在一个目录下搜索文件吗?
Hashim

@Hashim nope主要是-cos */*只匹配一个斜杠。如果您a/b在当前目录中有一个命名的文件,那么`* / *将与之匹配。
Criggie

0

这是一个跳过目录而不跳过所有错误的示例:

grep --directories='skip' 'searchString' *
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.