我想逐行读取文件并只存储一些值

I want to read a file line by line and store just some values

我有一个文件,其中以下内容重复了 n 次

>QDN;6135785008
-------------------------------------------------------------------------------
DN:;;;;;5785008;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TYPE:;SINGLE;PARTY;LINE
SNPA:;613;;;SIG:;DT;;;;LNATTIDX:;N/A;;;;;;;;;;;;;
LINE;EQUIPMENT;NUMBER:;;;;;BSAC;;39;0;00;01;;;
LINE;CLASS;CODE:;;IBN;;;
IBN;TYPE:;STATION
CUSTGRP:;;;;;;;;BSA_POS;;;;;SUBGRP:;0;;NCOS:;1
CARDCODE:;;V5LOOP;;;;GND:;N;;PADGRP:;NPDGP;;BNV:;NL;MNO:;N
PM;NODE;NUMBER;;;;;:;;;;80
PM;TERMINAL;NUMBER;:;;;;2
OPTIONS:
CWT;DGT;DDN;NOAMA;
;
-------------------------------------------------------------------------------
>QDN;6160160260
-------------------------------------------------------------------------------
DN:;;;;;0160260;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TYPE:;SINGLE;PARTY;LINE
SNPA:;616;;;SIG:;DT;;;;LNATTIDX:;N/A;;;;;;;;;;;;;
LINE;EQUIPMENT;NUMBER:;;;;;BSAC;;39;0;00;03;;;
LINE;CLASS;CODE:;;IBN;;;
IBN;TYPE:;STATION
CUSTGRP:;;;;;;;;BSA_POS;;;;;SUBGRP:;0;;NCOS:;15
CARDCODE:;;V5LOOP;;;;GND:;N;;PADGRP:;NPDGP;;BNV:;NL;MNO:;N
PM;NODE;NUMBER;;;;;:;;;;80
PM;TERMINAL;NUMBER;:;;;;4
OPTIONS:
CWT;3WC;DGT;DDN;NOAMA;
;
----

我想读取所有行并将一些值存储到 4 个变量中。例如; var number(由“>QDN”表示的行的第二列),var type(以 PARTY 开头的行),var snpa 和 var options(存储 OPTIONS 出现后的下一行的值)。输出可以是用分号分隔的文本文件(例如:var1;var2;var3;var4)。这是部分工作。我有以下代码,但无法将所有这些变量放在一起。我尝试在第一个循环中创建另一个 while 循环来验证循环的 'last' 检查(分隔信息块的分号),但它也没有用。

while IFS= read -r line || [[ -n "$line" ]]; read -r secondline; do
if [[ "$line" =~ ^'>QDN' ]]; then
    number=$(echo "$line" | awk -F ';' 'NF {print ;}')                
elif [[ "$line" =~ ^'TYPE' ]]; then
    type=$(echo "$line" | awk -F ';' 'NF {print " "" ";}')    
elif [[ "$line" =~ ^'SNPA' ]]; then
    snpa=$(echo "$line" | awk -F ';' 'NF {print ;}')  
elif [[ "$line" =~ ^'OPTIONS' ]]; then
    options=$(echo "${secondline}") 
fi  
echo $number";"$type";"$snpa";"$options         
done < "file.txt

上面代码的输出有些混乱:

;613;CWT;3WC;DGT;DDN;NOAMA;SACB;ACT;I976;$;$;N;
;613;CWT;3WC;DGT;DDN;NOAMA;SACB;ACT;I976;$;$;N;
;613;CWT;DGT;DDN;NOAMA;
;613;CWT;DGT;DDN;NOAMA;
;613;CWT;DGT;DDN;NOAMA;
;613;CWT;DGT;DDN;NOAMA;
;616;CWT;DGT;DDN;NOAMA;
;616;CWT;DGT;DDN;NOAMA;
;616;CWT;DGT;DDN;NOAMA;
;616;CWT;DGT;DDN;NOAMA;
;616;DGT;ARTY LINE
;616;DGT;ARTY LINE
;616;DGT;ARTY LINE    

你们谁能帮忙吗?

重复类似的 Awk 小片段通常表明您应该改用 Awk 重写整个脚本。

以下假定 OPTIONS 始终位于其他字段之后。取消这个限制并不难,但是有了这个,代码就异常简单了。

awk -F ';' 'BEGIN { OFS=";" }
   /^>QDN/ { number =  }
   /^TYPE/ { type =  " "  " "  }
   /^SNPA/ { snpa =  }
   /^OPTIONS/ { options = 1; next }
   options { print number, type, snpa, [=10=];
      number = type = snpa = options = "" }' file.txt

您可能应该单独从文件中删除 DOS 回车符 returns,但如果您也需要处理损坏的文件,在顶部添加 NF { sub(/\r/, "") } 很容易。

演示:https://ideone.com/zP102J

如果您在行读取循环中调用 awk,很可能您做错了。您应该考虑以普通 awk 或普通 bash 的形式进行。下面是一个普通的 bash 版本:

#!/bin/bash

while read -r line; do
    line=${line%$'\r'} # in case lines end in \r\n. Otherwise, you can remove this line
    case $line in
        \>QDN* | TYPE* ) printf %s "${line#*;};" ;;
        SNPA* ) line=${line#*;}; printf %s "${line%%;*};" ;;
        OPTIONS* ) read -r line && printf '%s\n' "$line" ;;
    esac
done < file.txt