grep / sed替换为空格不匹配

时间:2015-06-09 15:48:14

标签: bash awk sed grep

我正在使用以下信息填写信息的文件示例:

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),用semicolonn分隔以在Excel上导入它们。

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

问题是:当egrep与任何东西都不匹配时(比如server2的描述或server3的内存),myfile2中有一行的间隙......如何用空格替换它?

我想要的文件输出2:
server1的; Web服务器; 32GB
服务器2 ;; 128GB
服务器3;应用程序服务器;;

2 个答案:

答案 0 :(得分:2)

声音就像你需要的一样:

$ 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部分硬编码,但是字段的输出顺序依赖于它们在输入中出现的顺序,所以不是在这种情况下确定它是值得的。

答案 1 :(得分:1)

我认为不需要在输入数据上使用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数组来收集重要字段。

重要的是要注意,现在,我们假设您在结尾,而不是假设您将拥有“记忆”。 >开始每条记录。如果这个假设不正确,请说明您认为应该如何相互记录记录(即一个停止和下一个停止的位置)。例如,空行是一个选项。