You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Shell脚本读取文件提取指定字段输出异常求助

解决文本块提取变量并输出的问题

你的问题核心在于原脚本的行读取逻辑和输出时机错误,导致变量收集不完整且输出混乱。我们可以通过调整逻辑,等一个完整的信息块收集完所有变量后再输出,同时修正行读取的问题。

原脚本的核心问题

  • 同时使用两个read命令,导致行读取错位,每次循环会跳过一行内容
  • 每读取一行就输出一次,而不是等一个完整的信息块(从>QDN到OPTIONS下一行)的所有变量都收集完成后再输出
  • OPTIONS下一行的获取逻辑错误,没有正确定位到OPTIONS的下一行

方案1:修正Bash脚本

我们调整逻辑,遍历每一行,遇到新的>QDN块时先输出上一个块的结果(如果存在),然后重置变量;分别匹配各行收集对应变量,遇到OPTIONS行时读取下一行作为options,最后在脚本结束时输出最后一个块的结果:

#!/bin/bash

# 初始化变量
number=""
type=""
snpa=""
options=""

while IFS= read -r line || [[ -n "$line" ]]; do
    # 遇到新的QDN块,先输出上一个块的内容(如果变量都已收集)
    if [[ "$line" =~ ^'>QDN' ]]; then
        # 如果之前的变量都不为空,输出
        if [[ -n "$number" && -n "$type" && -n "$snpa" && -n "$options" ]]; then
            echo "$number;$type;$snpa;$options"
        fi
        # 重置变量
        number=""
        type=""
        snpa=""
        options=""
        # 提取number
        number=$(echo "$line" | awk -F ';' '{print $2}')
    elif [[ "$line" =~ ^'TYPE:' ]]; then
        # 提取type的第2、3、4列,用空格分隔
        type=$(echo "$line" | awk -F ';' '{print $2" "$3" "$4}')
    elif [[ "$line" =~ ^'SNPA:' ]]; then
        snpa=$(echo "$line" | awk -F ';' '{print $2}')
    elif [[ "$line" =~ ^'OPTIONS:' ]]; then
        # 读取下一行作为options
        IFS= read -r options
        # 去掉可能的末尾空格
        options=$(echo "$options" | sed 's/[[:space:]]*$//')
    fi
done < "file.txt"

# 输出最后一个块的内容
if [[ -n "$number" && -n "$type" && -n "$snpa" && -n "$options" ]]; then
    echo "$number;$type;$snpa;$options"
fi

方案2:使用Awk脚本(更高效简洁)

Awk天生适合处理这种结构化的文本块,我们可以把分隔线-------------------------------------------------------------------------------作为记录分隔符,然后在每个记录里提取需要的内容:

BEGIN {
    RS="-------------------------------------------------------------------------------"
    FS="\n"
    OFS=";"
}
{
    # 遍历当前记录的每一行
    for (i=1; i<=NF; i++) {
        line = $i
        if (line ~ /^>QDN/) {
            split(line, arr, ";")
            number = arr[2]
        } else if (line ~ /^TYPE:/) {
            split(line, arr, ";")
            type = arr[2]" "arr[3]" "arr[4]
        } else if (line ~ /^SNPA:/) {
            split(line, arr, ";")
            snpa = arr[2]
        } else if (line ~ /^OPTIONS:/) {
            # 下一行就是options内容
            options = $(i+1)
            # 去掉末尾空格
            gsub(/[[:space:]]*$/, "", options)
        }
    }
    # 只输出变量都存在的记录
    if (number != "" && type != "" && snpa != "" && options != "") {
        print number, type, snpa, options
    }
}

运行方式:

awk -f extract.awk file.txt > output.txt

预期输出

对于你提供的示例输入,运行后会得到:

6135785008;SINGLE PARTY LINE;613;CWT;DGT;DDN;NOAMA; 
6160160260;SINGLE PARTY LINE;616;CWT;3WC;DGT;DDN;NOAMA; 

内容的提问来源于stack exchange,提问作者hadesungod

火山引擎 最新活动