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


4

所有

我的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

任何指针都会有所帮助。

谢谢 沙

Answers:


4
    $ 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,即 file1.txtfile2.txt

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

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

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

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

1
grep -r … * 几乎总是写得更好 grep -r … .。如果当前目录中有太多文件等,则星号版本会变得很难看。
Eric

0

这会找到包含的文件 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 这样它只返回常规文件的名称。


感谢John的回答,但如果我必须在所有文件夹中进行搜索(递归)该怎么办。只添加“-r”的天气有效吗?
Sandeep K Gujje

@SandeepKGujje find,本身,对所有文件夹进行递归搜索。
John1024

0

你的问题标题是“包含”一个单词的文件。但是,在您的问题中,您确实提到“获取包含”一个单词的文件名。这些是不同的东西。幸运的是,它们都很简单,所以我只会告诉你们两者。

要查找包含单词的文件:

grep -iR“word1”。

-i说要忽略大小写。 -R是递归的(意味着搜索子目录)。 (大写字母由OpenBSD记录,更类似于ls,所以我更喜欢over -r。)句点指定从哪里开始查找。

要查找包含单词的文件名:

找 。 -我的名字 ” 字1

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

期间指定从哪里开始寻找。当前目录通常是一个不错的选择。

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

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

| grep -v word99>> output.txt的

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

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

grep -iR“word1”。 | grep -v word99>> output.txt的
找 。 -我的名字 ” 字1 “| grep -v word99>> output.txt

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

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

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.