Shell 命令查找包含一个单词但不包含第二个单词的文件

Shell 命令查找包含一个单词但不包含第二个单词的文件

全部

我的 Linux 机器中有以下两个文件,我想找出包含“word1”但不包含“word99”的文件

file1.txt
  word1
  word2
  word3
  word4
  word5

file2.txt
  word1
  word2
  word3
  word99

我一直在使用以下命令来获取包含“word1”的文件,但找不到任何有关如何修改它以获取包含“word1”但不包含“word99”的文件名的信息

find . -name '*.*' -exec grep -r 'word1' {} \; -print > output.txt

任何指点都会有帮助。

谢谢桑迪

答案1

    $ grep -lr 'word1' * | xargs grep -L 'word99'
    file1.txt

在哪里:

    -l, --files-with-matches
         Only the names of files containing selected lines are written
         to standard output.
    -R, -r, --recursive
         Recursively search subdirectories listed.
    -L, --files-without-match
         Only the names of files not containing selected lines are written
         to standard output.

在管道之前的命令的第一部分中,我们得到:

    $ grep -lr 'word1' * 
    file1.txt
    file2.txt

上述命令递归解析子目录内的文件,并列出包含单词word1、 iefile1.txt和 的文件file2.txt

稍后在第二部分中| xargs grep -L 'word99',管道发送file1.txtfile2.txt作为输入到,xargs并将它们grep作为参数提供给。然后列出不包含使用该选项grep的文件,即。word99-Lfile1.txt

这里我们需要xargs,因为在命令的第一部分,我们得到了file1.txtfile2.txt作为 stdout 上的输出。我们需要解析这些文件的内容,而不是字符串file1.txtfile2.txt

以下命令也给出相同的结果(反转我们搜索/排除字符串的方式):

      $ grep -Lr 'word99' * | xargs grep -l 'word1'
      file1.txt

答案2

这将查找包含以下内容的文件word1

$ find . -name '*.*' -type f -exec grep -q 'word1' {} \; -print
./file1.txt
./file2.txt

这将查找包含word1以下内容的文件:不是 word99

$ find . -name '*.*' -type f -exec grep -q 'word1' {} \; '!' -exec grep -q 'word99' {} \; -print 
./file1.txt

要将输出保存在文件中:

find . -name '*.*' -type f -exec grep -q 'word1' {} \; '!' -exec grep -q 'word99' {} \; -print >output.txt

对于包含 的文件,测试-exec grep -q word99 {} \;将返回 True word99。我们!在它前面加上 来否定返回值。因此,! -exec grep -q word99 {} \;对于包含 的文件,测试将返回 True不是word99!用单引号引起来是因为,如果打开了历史扩展,!可以是 shell 活动字符。

笔记:

  1. -q添加了选项以使其grep安静。使用-q,grep 将设置正确的退出代码,但不会在 stdout 上显示匹配的行。

  2. -type f添加测试以便find它仅返回常规文件的名称。

答案3

您的问题标题说的是“包含单词的文件”。但是,在您的问题中,您确实提到了“获取包含单词的文件名”。这是两码事。幸运的是,它们都相当简单,所以我将简单地向您展示两者。

查找包含单词的文件:

grep -iR“单词1”。

-i 表示忽略大小写。-R 是递归的(表示搜索子目录)。(OpenBSD 记录了大写字母,它与 ls 更相似,所以我更喜欢大写字母而不是 -r。)句点指定从哪里开始查找。

查找包含单词的文件名:

查找 .-iname "单词1

-iname 是“name”的不区分大小写的版本。

句点指定从哪里开始查找。当前目录通常是一个不错的选择。

注意:您引用了““在您的一个示例中。这对于 DOS 来说很棒,在 Microsoft Windows 中通常也很好,但对于 Unix 环境来说,这是一个非常坏的习惯。看到这一点,我觉得您熟悉 Windows。好吧,请理解,在 Windows 中,“FIND”(或“find”)定位文件中的文本。Unix 则不同:“grep”定位文件中的文本,“find”定位文件名。

现在,要排除单词 99,并将其放在文本文件中,请添加以下文本:

| grep -v word99 >> 输出.txt

这是管道键,几乎总是 Shift-Backslash。

因此,举个例子,如果您想同时执行这两项操作,请使用:

grep -iR "word1" . | grep -v word99 >> output.txt
查找 . -iname "单词1“|grep -v word99>>输出.txt”

管道符之前的部分将运行命令,并将输出发送到 Unix 样式的管道。然后,内容从管道发送到下一个命令的标准输入。grep -v 将查看它收到的标准输入,并排除您想要的内容。grep -v 将其余结果发送到其标准输出。>> 将把前一个命令的标准输出重定向到指定文本文件的末尾。

您之所以没有在“find”命令中看到有关如何排除文本的文档选项,是因为 Unix 在设计时就非常注重简化程序,并使用管道技术来产生复杂的效果。在 Microsoft 环境中,旧的 Microsoft 代码在管道处理方面特别麻烦,因此程序基本上试图将更多功能整合到每个程序中。一方面,这对最终用户来说似乎更简单(所有功能都内置),但这种方法缺乏一致性。当您使用 Unix 时,不要害怕管道:一旦您习惯了它,您可能会发现它大大简化了事情,但因为您可以在许多情况下使用简单的工具,所以您不需要一遍又一遍地重新学习简单的技术(针对每个不同的程序)。

相关内容