从文件b中的文件a中查找单词,并从文件

时间:2017-08-02 14:20:37

标签: bash awk grep

我有两个文件,我试图运行find / grep / fgrep。我一直在尝试几种不同的命令来尝试获得以下结果:

文件A

hostnamea
hostnameb
hostnamec
hostnamed
hostnamee
hostnamef

档案B

hostnamea-20170802
hostnameb-20170802 
hostnamec-20170802.xml # some files have extensions
020214-_hostnamed-20170208.tar # some files have different extensions and have different date structure
HOSTNAMEF-20170802

* about files- date = 20170802 - 大多数都有这种日期格式 - 有些日期格式不同*

FileA是我的控制文件 - 我想用整个单词hostnamea-f搜索fileb并匹配fileb中的hostnamea-f,并将filea中的不匹配输出到终端上的输出在shell脚本中使用。

对于这个例子,我做了hostnamee不在fileb中。我想运行一个fgrep / grep / awk - 无论什么都适用于此 - 并且只从filea输出缺少的hostnamee

我可以让它发挥作用,但它并没有特别做我需要的东西,如果我换掉它我什么也得不到。

user@host:/netops/backups/scripts$ fgrep -f filea fileb -i -w -o
hostnamea
hostnameb
hostnamec
hostnamed
HOSTNAMEF

很酷 - 我在File-B中获得了匹配但是如果我试图反转它会怎么样。

host@host:/netops/backups/scripts$ fgrep -f fileb filea -i -w -o
host@host:/netops/backups/scripts$ 

我尝试过几种不同的命令,但似乎无法正确使用。我使用-i忽略大小写,-w匹配整个单词和-o

我找到了某种解决方法,但希望有一种更优雅的方法,可以使用awk,egrep,fgrep或其他命令执行此操作。

user@host:/netops/backups/scripts$ fgrep -f filea fileb -i -w -o >   test
user@host:/netops/backups/scripts$ diff filea test -i

5D4 < hostnamee

2 个答案:

答案 0 :(得分:3)

你可以

  • 寻找"仅匹配",即-o,a b
  • 将结果用作在a中查找的模式,即-f-
  • 仅列出不匹配的内容,即-v

代码:

grep -of a.txt b.txt | grep -f- -v a.txt

输出:

hostnamee
hostnamef

不区分大小写的代码:

grep -oif a.txt b.txt | grep -f- -vi a.txt

输出:

hostnamee

编辑:
为了回应Ed Morton的有趣输入,我已经将样本输入稍微变得更糟糕了#34;测试子字符串匹配和正则表达式活动字符的稳健性(例如"。"):

A.TXT:

hostnamea
hostnameb
hostnamec
hostnamed
hostnamee
hostnamef
ostname
lilihostnamec
hos.namea

b.txt:

hostnamea-20170802
hostnameb-20170802 
hostnamec-20170802.xml # some files have extensions
020214-_hostnamed-20170208.tar # some files have different extensions and have different date structure
HOSTNAMEF-20170802
lalahostnamef
hostnameab
stnam

这使事情变得更有趣。 我提供了这种不区分大小写的解决方案:

grep -Fwoif a.txt b.txt | grep -f- -Fviw a.txt
  • 额外的-F,意思是"没有正则表达式技巧"
  • 额外-w,意思是"全字匹配"

我发现输出非常令人满意,假设"要求的变化如下"被接受:
主持人在" a"只匹配" b"的部分内容,如果所有相邻的_(以及其他"单词characers"始终被视为主机名的一部分。
(注意hostnamed的附加输出行,现在在" b"中找不到了,因为在" b"中,它前面有一个_ 。)
为了匹配可能出现的有效主机名,这些主机名前面/后面跟着其他单词字符,列表在" a"必须明确地命名这些变化。例如。 " _hostnamed"必须列出才能没有"主机名"在输出中。 (运气不错,这对于OP来说甚至可以接受,那么建议使用这个扩展解决方案;对于#Ed; EdMortonish陷阱的强健性" .Ed,请考虑这是对你有趣输入的赞美,这并不意味着无论如何都是消极的。)

" nasty"的输出a和b:

hostnamed
hostnamee
ostname
lilihostnamec
hos.namea

我不确定_的更改处理是否仍然与OP目标相匹配(如果不是,在OP范围内,第一个不区分大小写的解决方案是否令人满意)。 _是"字母字符的一部分"这可以用于"全字只匹配" -w。更多详细的正则表达式控制在某些方面超出了grep,正如Ed Morton提到的那样,使用awk,perl(sed用于受虐狂的大脑锻炼,我喜欢的那种)是合适的。

在Windows上使用GNU grep 2.5.4。 文件a.txt和b.txt包含你的内容,但我确保它们有UNIX行结尾,这很重要(至少对于a,可能不是b)。

答案 1 :(得分:2)

$ cat tst.awk
NR==FNR {
    gsub(/^[^_]+_|-[^-]+$/,"")
    hostnames[tolower($0)]
    next
}
!(tolower($0) in hostnames)

$ awk -f tst.awk fileB fileA
hostnamee

$ awk -f tst.awk b.txt a.txt
hostnamee
ostname
lilihostnamec
hos.namea

上述唯一的假设是,您的主机名不包含下划线,并且该行的最后一个-之后的任何内容都是日期。如果情况并非如此,并且可以更好地定义fileB中可选的主机名前缀和后缀字符串,那么只需调整gsub()即可使用适当的正则表达式。

相关问题