2017-08-02 93 views
2

我有两个文件,我试图运行find/grep/fgrep。我一直在尝试几个不同的命令,试图得到如下结果:从文件b中找出文件a中的单词,并从文件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 

*有关文件 - 日期= 20170802 - 大多数都有这样的日期格式 - 一些有不同的日期格式*

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

对于这个例子,我做到了hostnamee不在fileb中。我想运行一个fgrep/grep/awk - 无论如何可以工作 - 并只输出filea中缺失的hostnamee

我可以得到这个工作,但它并不特别做我所需要的,如果我交换它,我什么也得不到。

[email protected]:/netops/backups/scripts$ fgrep -f filea fileb -i -w -o 
hostnamea 
hostnameb 
hostnamec 
hostnamed 
HOSTNAMEF 

很酷 - 我得到了File-B中的匹配,但是如果我尝试反转它,该怎么办?

[email protected]:/netops/backups/scripts$ fgrep -f fileb filea -i -w -o 
[email protected]:/netops/backups/scripts$ 

我尝试了几个不同的命令,但似乎无法弄清楚。我使用-i来忽略大小写,-w匹配整个单词和-o

我找到了一些解决方法,但希望有一个更优雅的方法来做到这一点,使用单个命令awk,egrep, fgrep或其他。

[email protected]:/netops/backups/scripts$ fgrep -f filea fileb -i -w -o > test 
[email protected]:/netops/backups/scripts$ diff filea test -i 

5D4 < hostnamee

+0

在我的真实情况下 - 上面的这个工作甚至不像上面的例子那样工作。我在文件名中也有 - 和_,并且它似乎没有给出与上述相同的结果。 –

+0

你想'HOSTNAMEF'被认为是匹配'hostnamef'吗?即不区分大小写? – Yunnosch

+0

是的 - 在这种情况下,一些备份文件的例子 - 在大写完成,而我的主机文件都是小写 - 所以HOSTNAMEF应=主机名 –

回答

3

您可以

  • 寻找 “只-匹配”,即-o,一个在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的有趣输入,我已经使示例输入有点“nastier”来测试针对子字符串匹配和正则字符活动字符(例如, “”):

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”的部分匹配,如果全部相邻_ (和其他“单词主人公”总是被认为是主机名的一部分。
(请注意,hostnamed的附加输出行现在不再在“b”中找到,因为在“b”中,它前面有一个_)。
要匹配可能出现的有效主机名,通过其他单词字符,“a”中的列表将不得不明确地命名这些变体。例如。必须列出“_hostnamed”才能在输出中没有“主机名”。 (运气好的话,OP甚至可以接受,那么推荐使用这个扩展的解决方案;为了抵抗“EdMortonish陷阱”的可靠性,Ed,请认为这是对你有趣的输入的补充,但这并不意味着任何负面的。)

输出为“肮脏” a和b:

hostnamed 
hostnamee 
ostname 
lilihostnamec 
hos.namea 

我不知道改变的处理的_是否仍然符合有机磷农药的目标(如果没有,OP的范围内第一个不区分大小写的解决方案满足)。 _是“字母字符”的一部分,可用于“全字匹配”-w。正如Ed Morton所提到的,更详细的正则表达式控制在某些方面已经超越了grep,因此使用awk,perl(sed用于受虐狂的大脑练习,我喜欢的那种)是适当的。

在Windows上使用GNU grep 2.5.4。 文件a.txt和b。txt有你的内容,但我确定他们有UNIX行结束,这很重要(至少对于a而言,可能不适用于b)。

+0

grep -of file1 file2 -i | grep -f- -v file1 -i(这似乎是用您的命令示例添加忽略大小写的正确方法) –

+0

我提供了一个不区分大小写的版本(在注意到您的评论问题之前)。 – Yunnosch

+0

这将做到 - 谢谢你的答案 –

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()即可使用适当的正则表达式。

+0

嗯,还需要一个假设,真是可惜,但基于这个假设,它和我的解决方案一样有效(基于我的假设),谢谢你提供一个替代角度,我想我看到了一个非常早期的,几乎透彻的评论,预测了我们两个人遇到的问题。可惜它被删除了。 – Yunnosch

+0

它只需要一个假设,因为OP尚未告诉我们任何方式来区分主机名与前缀或后缀。必须有一个强大的方法,但我们需要OP来告诉我们这是什么。它不能假设的是主机名的值,这就是为什么它比grep解决方案更好。 (提高健壮性的证据是,在greps +管道解决方案时,这不会错误地显示'hostnamed' :-))。 –

+0

它仍然适用于主机名为_的ogirinal解决方案:user @ host:/ netops/backups/scripts $ find/dir -type f -mtime -.9 -printf'%f \ n'| fgrep -eacs - eTFTP> fileb#我把这些文件放到fileb中 - 比如host22,hostx,hosty host22-crappyname-170803-0005.tar.gpg 2017-08-03-00-05-05_hostx_UCM_TFTP.tar 2017-08-03- 00-05-05_hosty_UCM_TFTP.tar用户@主机:/ netops/backups/scripts $ cat $ mh hosta hsotb#不会将hostx或hosty与上面的_一起装载到fileb中,因此它匹配并执行它的工作与文件2匹配_在其中。 –

相关问题