awk - printf 的问题

awk - printf 的问题

(编辑:问题已解决,我在 Mac 上使用了 Windows 生成的文件,问题是行结尾。在 Studio 代码中打开文件并设置正确的行结尾为我解决了这个问题)

我有ProduKey我想要处理的生成的文件awk

ProduKey 产生如下输出:

==================================================
Product Name      : Microsoft Office Professional 2013
Product ID        : 00000-00000-00000-00000
Product Key       : 00000-00000-00000-00000-00000
Installation Folder : C:\Program Files\Microsoft Office\Office15\
Service Pack      : 
Build Number      : 
Computer Name     : PC-000-0
Modified Time     : 06.12.2018 14:03:44
==================================================

==================================================
Product Name      : Windows 10 Pro
Product ID        : 00000-00000-00000-00000
Product Key       : 00000-00000-00000-00000-00000
Installation Folder : C:\Windows
Service Pack      : 
Build Number      : 17763
Computer Name     : PC-000-0
Modified Time     : 18.07.2019 09:50:37
==================================================

我想从中生成 csv 文件,以便稍后将密钥、计算机名称和产品名称存储到数据库中。

所以可能的 csv 可能如下所示:

PC-000-0;Microsoft Office Professional 2013;00000-00000-00000-00000-00000

到目前为止我的方法:

    BEGIN {
    RS="\n\n";
    FS="\n";
}
{
    if ($1 ~ /Product Name/) {
        split($1,productArray,":")
        product = productArray[2]
    }

    if ($1 ~ /Product Key/) {
        split($1,keyArray,":")
        key = keyArray[2]
    }

    if ($1 ~ /Computer Name/ ) {
        split($1,computerArray,":")
        computer = computerArray[2]
        #print product 
        #print key
        #print computer
        printf("\n")
        printf("%s ; %s ; %s \n", computer, product, key)
    }
}

我的问题是我无法连接字符串。或者也许当我想打印它们时字符串被覆盖?我花了几个小时在这上面,非常感谢您的帮助/提示。

如果有更优雅的方法来实现我的目标,请随时告诉我。

我在 Mac 上使用awk(awk 版本 20070501),但我也有一个 Linux 盒子。

提前致谢。

答案1

您可以在这里使用 awk 的记录分隔符 ( RS)。将其设置为==================================================={50}是相同的东西,但作为正则表达式,可以让您将与单个产品关联的每组值视为单个“行”。如果您随后将输出字段分隔符 ( OFS) 设置为;并将输入字段分隔符 (FS-F选项) 设置为\n(换行符) 或:,那么您可以执行类似这样的小技巧(使用 GNU awk):

$ awk RS='={50}' \
      -v OFS=';' \
      -F'[\n:]' \
      'NR%2==0{print $16,$3,$7}' file 
 PC-000-0; Microsoft Office Professional 2013; 00000-00000-00000-00000-00000
 PC-000-0; Windows 10 Pro; 00000-00000-00000-00000-00000

由于每个条目上面有一个=============================================(50 =) ,下面有一个,所以我们只想读取每一秒“行”。这就是NR%2==0支票的作用。

那里有一些额外的空格,一个位于每个行的开头,另一个位于字段之间。如果它们有问题,您可以使用以下方法删除它们sed

$ awk -v RS='={50}' \
      -v OFS=';' \
      -F '[\n:]' \
      'NR%2==0{print $16,$3,$7}' file | 
        sed -e 's/^ //' -e 's/; /;/g'
PC-000-0;Microsoft Office Professional 2013;00000-00000-00000-00000-00000
PC-000-0;Windows 10 Pro;00000-00000-00000-00000-00000

使用正则表达式是RSGNU 扩展,因此可能不适用于您的 macOS。如果没有,请尝试以下操作:

$ awk -v RS='=' \
      -v OFS=';' \
      -F'[\n:]' \
     'NR%50==1 && $2{print $16,$3,$7}' file |
        sed -e 's/^ //' -e 's/; /;/g'

答案2

您可以尝试以下操作:

awk -F' : ' '/^Product Name/{pn=$2}
             /^Product Key/{pk=$2}
             /^Computer Name/{print $2,pn,pk}' OFS=\; file

字段分隔符FS设置为:以便通过 获取字段值$2

输出字段分隔OFS符设置为;

Computer Name每次找到关键字时都会打印该字符串。

答案3

正确的方法是创建一个数组,用于存储标签名称到值映射(f[]如下),然后在每个记录的末尾打印您想要的任何值,例如:

$ cat tst.awk
BEGIN { OFS=";" }
{
    sub(/\r$/,"")
    tag = val = $0
    sub(/[[:space:]]*:.*/,"",tag)
    sub(/[^:]+[[:space:]]*:[[:space:]]*/,"",val)
    f[tag] = val
}
/^=/ && (cnt++)%2 {
    print f["Computer Name"], f["Product Name"], f["Product Key"]
    delete f
}

$ awk -f tst.awk file
PC-000-0;Microsoft Office Professional 2013;00000-00000-00000-00000-00000
PC-000-0;Windows 10 Pro;00000-00000-00000-00000-00000

如果您愿意,使用相同的方法也可以轻松将整个输入文件转换为 CSV:

$ cat tst.awk
BEGIN { OFS=";" }
!/^=/ {
    sub(/\r$/,"")
    tag = val = $0
    sub(/[[:space:]]*:.*/,"",tag)
    sub(/[^:]+[[:space:]]*:[[:space:]]*/,"",val)
    if ( !seen[tag]++ ) {
        tags[++numTags] = tag
    }
    f[tag] = val
}
/^=/ && (cnt++)%2 {
    if ( !doneHdr++ ) {
        for (tagNr=1; tagNr<=numTags; tagNr++) {
            tag = tags[tagNr]
            printf "\"%s\"%s", tag, (tagNr<numTags ? OFS : ORS)
        }
    }

    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = tags[tagNr]
        printf "\"%s\"%s", f[tag], (tagNr<numTags ? OFS : ORS)
    }

    delete f
}

$ awk -f tst.awk file
"Product Name";"Product ID";"Product Key";"Installation Folder";"Service Pack";"Build Number";"Computer Name";"Modified Time"
"Microsoft Office Professional 2013";"00000-00000-00000-00000";"00000-00000-00000-00000-00000";"C:\Program Files\Microsoft Office\Office15\";"";"";"PC-000-0";"06.12.2018 14:03:44"
"Windows 10 Pro";"00000-00000-00000-00000";"00000-00000-00000-00000-00000";"C:\Windows";"";"17763";"PC-000-0";"18.07.2019 09:50:37";""

更改OFS=";"OFS=",",输出将是一个文件,您可以在 Windows 中双击以使其在 Excel 中正确显示。

相关内容