【问题标题】:grep/sed replace no match with blank spacegrep/sed 用空格替换不匹配
【发布时间】:2015-06-09 15:48:13
【问题描述】:

我在其中获取信息的文件示例:

name : server1
description : webserver
memory : 32gb

name : server2
memory : 128gb

name : server3
description : appserver

我正在做这样的事情:

cat myfile | egrep -w "name|description|memory" | awk -F" " '{print $3}' >> myfile2

为了从 myfile 的第二列取回信息。

然后,我将 myfile2 格式化为在一行中包含来自每个服务器的信息(使用 tr 替换 CRLF),用分号分隔以将它们导入 Excel。

myfile2:
server1;webserver;32gb
server2;128gb
server3;appserver

问题是:当 egrep 不匹配任何内容时(如 server2 的描述或 server3 的内存),myfile2 中有一行空白...如何将其替换为空格?

需要我的文件 2 的输出:
server1;网络服务器;32gb
服务器2;;128GB
server3;appserver;;

【问题讨论】:

  • 您能否edit 向我们展示您所显示的输入所需的输出究竟是什么?
  • 这听起来有点像XY Problem。您在此处真正想做什么,以及将如何使用这些数据?正如 Tom 建议的那样,请提供您正在寻找的输出变化的示例。
  • grep -v "^$" 将排除空行。
  • 帖子已编辑。当没有什么要 grep 时(例如 server2 的描述或 server3 的内存),我现在只想放一个分号以便创建一行,即使其中没​​有信息。
  • 您的预期输出中的“server3”来自哪里?确保预期输出与示例输入匹配。

标签: bash awk sed grep


【解决方案1】:

听起来你只需要:

$ awk -v RS= -F' *: *|\n' -v OFS=';' '{print $2,$4,$6}' myfile
server1;webserver;32gb
server2;;128gb

如果你想要 CRLF 行结尾,那么只需在前面添加 -v ORS='\r\n' 告诉 awk。

不知道为什么你还没有更新你的问题,但听起来这是你真正需要的:

$ cat file  
name : server1
description : webserver
memory : 32gb

name : server2
memory : 128gb

name : server3
description : appserver

.

$ cat tst.awk
BEGIN{
    RS=""
    FS=" *: *|\n"
    OFS=";"
    numNames = split("name description memory",names,/ /)
    for (i=1; i<=numNames; i++) {
        name2nr[names[i]] = i
    }
}
{
    delete vals
    for (i=1;i<=NF;i+=2) {
        vals[name2nr[$i]] = $(i+1)
    }
    for (i=1; i<=numNames; i++) {
        printf "%s%s", vals[i], (i<numNames?OFS:ORS)
    }
}

$ awk -f tst.awk file
server1;webserver;32gb
server2;;128gb
server3;appserver;

可以编写添加第一遍,只计算字段名称,而不是在 BEGIN 部​​分硬编码它们,但是字段的输出顺序取决于它们在输入中出现的顺序,所以不在这种情况下肯定是值得的。

【讨论】:

  • 谢谢,这对我来说听起来不错 :) 但是,我在示例中犯了一个错误。事实上,当没有数据时,该字段是隐藏的。所以对于 server2 :name : server2 memory : 128gb 在没有 server2 描述的情况下。这就是为什么我要做一个 grep 来开始。因为在您的示例中 print $4 变为“128gb”,而对于另一台服务器,它是描述。
  • 抱歉,我不知道您所说的when there is no data the field is hidden 是什么意思。如果您的示例不正确或不完整,请编辑您的问题以提供更好的示例。
  • 我的意思是如果没有为服务器指定描述或内存,则文件上不会出现“描述”或“内存”字段。所以这并不是我在第一篇文章中描述的那样。
  • 好的,那么,再次更新您的帖子以准确无误,以便我们能够最好地帮助您和本问答的未来读者。
【解决方案2】:

我认为没有必要在您的输入数据上使用 grepawk 命令几乎可以做grep 可以做的所有事情。考虑以下几点:

awk -F' *: *' '
  {
    a[$1]=$2;
  }

  /^memory/ {
    printf("%s;%s;%s\n", a["name"], a["description"], a["memory"]);
    delete a;
  }' myfile

这里的组件如下:

  • -F... 设置字段分隔符,包括空格。
  • a[$1]=$2 使用每条记录中的数据填充一个短期数组。
  • /^memory/ 仅在每组的最后一行执行此配方...
  • printf(...) 显示您的输出,并且
  • delete a 让您从下一个多行记录重新开始。

您当然可以将所有内容压缩到一行中:

awk -F' *: *' '{ a[$1]=$2 } /^memory/ { printf("%s;%s;%s\n", a["name"], a["description"], a["memory"]); delete a }' myfile

这是你需要的吗?

更新

我看到您已修改您的问题以包含与上述解决方案支持的不同的示例数据。这是一个适用于当前示例的更新:

function outp() {
        printf("%s;%s;%s\n", a["name"], a["description"], a["memory"]);
}

BEGIN {
        seen=0;
        FS=" *: *";
}

/^name/ && seen {
        outp();
        delete a;
}

/^name/ {
        seen=1;
}

{
        a[$1]=$2;
}

END {
        outp();
}

这使用了一个函数 (outp()) 来简化事情。它使用seen 变量来确定脚本是否已经看到任何实际数据(否则,/^name/ 的第一个匹配将生成空输出)。并且它继续使用a 数组来收集重要的字段。

重要的是要注意,现在,我们假设您在每条记录的 end 处都有一个“记忆”,而不是假设您将在 处有一个“名称” >开始每条记录。如果这个假设不正确,请说明您认为应该如何区分记录(即一个停止和下一个从哪里开始)。例如,空行是一个选项。

【讨论】:

  • 我已经更新了我的答案,以反映您问题中更新的示例数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-05
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-02
  • 2012-10-24
相关资源
最近更新 更多