【问题标题】:While loop on each sed match在每个 sed 匹配时循环
【发布时间】:2014-04-29 03:13:48
【问题描述】:

我正在尝试解析存储在本地工作站上的电子邮件文件。每个文件都包含一个硬件订单列表。某些文件可能在一个块中包含多个硬件列表,该块以 Processor: 开头并以 ExtraIp: 结尾。如果电子邮件仅包含一个块,我当前的脚本可以正常工作。当电子邮件文件包含如上所述的多个数据块时,就会出现问题。

示例问题电子邮件:

Processor: Intel Xeon E3-1270 V2 3.5GHZ, Quad Core
RAM: 16GB DDR3 SDRAM
HD1: 2 x SATA Hardware RAID 1 (7,200 rpm)
(+1TB 7200 RPM SATA hard drive)
SSD: No SSD Drive
HD2: SATA Backup Drive
(+1 TB SATA (7,200 rpm))
HD3: No Additional Storage Array
ExtraIp: Public IP Addresses

Processor: Intel Xeon E3-1220 V2 3.1GHZ, Quad Core
RAM: 8GB DDR3 SDRAM
HD1: 2 x SATA Hardware RAID 1 (7,200 rpm)
(+1TB 7200 RPM SATA hard drive)
SSD: No SSD Drive
HD2: No Backup Drive
HD3: No Additional Storage Array
ExtraIp: Public IP Addresses

我的脚本:

#!/bin/bash
find ./email -print0 | while read -d $'\0' file
do
#### Sed and while loop here, with modification to the below lines to read data from the while loop instead of directly from each file ####
#### Example sed command: sed -n "/Processor:/,/ExtraIp:/p" $file ####

    order_date=$(echo $file | awk '{print $11}')
    grep "Processor:" "$file" | cut -d : -f2 | cut -d , -f1 | while read cpu_type
    do
            if [ "$cpu_type" != "" ]; then
                    echo $order_date
                    echo $cpu_type
                    ram_size=$(grep "RAM:" "$file" | cut -d : -f2)
                    if [ "$ram_size" != "" ]; then
                            echo $ram_size
                    fi
                    hd1_type=$(grep "HD1:" "$file" | cut -d : -f2)
                    if [ "$hd1_type" != "" ]; then
                            echo $hd1_type
                    fi
                    hd1_size=$(grep -A1 "HD1:" "$file" | tail -n1)
                    if [ "$hd1_size" != "" ]; then
                            echo $hd1_size
                    fi
                    ssd_type=$(grep "SSD:" "$file" | cut -d : -f2)
                    ssd_type1=$(grep "SSD:" "$file" | cut -d : -f2 | awk '{print $1}')
                    if [ "$ssd_type" != "" ]; then
                            echo $ssd_type
                    fi
                    if [[ "$ssd_type1" != "No"  &&  "$ssd_type1" != "" ]]; then
                            ssd_size=$(grep -A1 "SSD:" "$file" | tail -n1)
                            echo $ssd_size
                    else
                            ssd_size="No SSD"
                            echo $ssd_size
                    fi
                    hd2_type=$(grep "HD2:" "$file" | cut -d : -f2)
                    hd2_type1=$(grep "HD2:" "$file" | cut -d : -f2 | awk '{print $1}')
                    if [ "$hd2_type" != "" ]; then
                            echo $hd2_type
                    fi
                    if [[ "$hd2_type1" != "No"  &&  "$hd2_type1" != "" ]]; then
                            hd2_size=$(grep -A1 "HD2:" "$file" | tail -n1)
                            echo $hd2_size
                    else
                            hd2_size="No HD2"
                            echo $hd2_size
                    fi
                    hd3_type=$(grep "HD3:" "$file" | cut -d : -f2)
                    hd3_type1=$(grep "HD3:" "$file" | cut -d : -f2 | awk '{print $1}')
                    if [ "$hd3_type" != "" ]; then
                            echo $hd3_type
                    fi
                    if [[ "$hd3_type1" != "No"  &&  "$hd3_type1" != "" ]]; then
                            hd3_size=$(grep -A1 "HD3:" "$file" | tail -n1)
                            echo $hd3_size
                    else
                            hd3_size="No HD3"
                            echo $hd3_size
                    fi
            echo "$order_date,$cpu_type,$ram_size,$hd1_type,$hd1_size,$hd2_type,$hd2_size,$hd3_type,$hd3_size" >> order_list.csv
            fi
    done
done

预期输出:

如果电子邮件只包含一个文本块,我会得到正确的输出:

2014-04-01,Intel Xeon E3-1270 V2 3.5GHZ, 16GB DDR3 SDRAM, 2 x SATA Hardware RAID 1 (7,200 rpm),(+1TB 7200 RPM SATA hard drive), SATA Backup Drive,(+1 TB SATA (7,200 rpm)), No Additional Storage Array,No HD3

如果电子邮件包含多个文本块,我会得到以下输出:

2014-04-01,Intel Xeon E3-1270 V2 3.5GHZ, 16GB DDR3 SDRAM
8GB DDR3 SDRAM, 2 x SATA Hardware RAID 1 (7,200 rpm)
2 x SATA Hardware RAID 1 (7,200 rpm),    (+1TB 7200 RPM SATA hard drive), SATA Backup Drive
No Backup Drive,    HD3: No Additional Storage Array, No Additional Storage Array
No Additional Storage Array,    ExtraIp: Public IP Addresses
2014-04-01,Intel Xeon E3-1220 V2 3.1GHZ, 16GB DDR3 SDRAM
8GB DDR3 SDRAM, 2 x SATA Hardware RAID 1 (7,200 rpm)
2 x SATA Hardware RAID 1 (7,200 rpm),    (+1TB 7200 RPM SATA hard drive), SATA Backup Drive
No Backup Drive,    HD3: No Additional Storage Array, No Additional Storage Array
No Additional Storage Array,    ExtraIp: Public IP Addresses

在第二个输出中,两个文本块的数据为每个 CSV 值(内存和驱动器)复制。我的计划是从 sed 命令中包含另一个 while 循环(放置在我脚本中上述注释的空间中),然后修改每个命令以从 while 循环中读取数据。

使用的示例 sed 命令:

sed -n "/Processor:/,/ExtraIp:/p" $file

【问题讨论】:

  • 如果您在运行sed 之前向我们展示数据会更好,然后您希望在决赛中得到什么。也许awk 可以一次性完成所有操作,而无需while loop
  • (一小部分)示例输入(涵盖所有相关案例)、该示例所需的输出、您的代码、您的错误消息、您的输出是一个很好的问题。祝你好运。

标签: sed while-loop


【解决方案1】:

您的解析脚本使用grep 提取一个字段,当$file 包含两个相同的字段时,grep 同时提取它们。

您最好重构以在 Awk 中进行所有解析。我不会为你完成它,但这应该是一个好的开始。

awk 'BEGIN { split("Processor:RAM:HD1:SSD:HD2:HD3", f, /:/) }
    /^Processor:/ { delete a }  # forget any prevous record
    /^(Processor|RAM|HD[123]|SSD):/ { i=$1; sub(/:/,"",i); 
        $1=""; sub(/^ /,""); a[i]=$0 }
    i ~ /^(HD[123]|SSD)$/ && $1 == "No" { a[i] = "No " i; i=""; next }
    i ~ /^(HD[123]|SSD)$/ && !k { k=i; next }  # remember key for two-line entry
    k { a[k] = a[k] "," $0; k=i="" }
    /^ExtraIp: / {s=""; for (i=1; i<=length(f); i++) {
        printf("%s%s", s, a[f[i]]); s="," } printf "\n" }' "$file"

【讨论】:

  • 这帮助我找出了我的问题,使用 grep 来计算处理器的出现次数,使用 awk 通过循环运行该计数,以根据 grep 计数选择每个块并解析出所需的数据。
  • 我拼凑的脚本可以解析任意数量的记录并打印每个记录。应该不需要单独的grep(如果有,如果我还没有这样做,它应该被考虑到 Awk 脚本中)。您可能需要对其进行调整以正确忽略电子邮件标题等,但在while read file 循环中应该或多或少地需要这样的东西。
猜你喜欢
  • 2020-08-12
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
  • 2017-04-25
  • 2013-02-07
相关资源
最近更新 更多