【问题标题】:Find field length from one file and extract the same length of data from another fixed length file and store the field and data in new file从一个文件中查找字段长度并从另一个固定长度文件中提取相同长度的数据并将字段和数据存储在新文件中
【发布时间】:2020-09-22 04:42:02
【问题描述】:

我有一个文件file1.dml 和另一个固定长度的数据文件file2.dat。 file1.dml 中的数据是这样的

start
  integer(16) field1 ;
  string(1) filed2 ;
  string(80) filed3 ;
  decimal(16.2) field4;
  string(1) newline = "\n";
end;

file2.dat 中的数据类似于

12345678        ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB                                         1234567890      

我需要如下的输出文件

field1="12345678        "
filed2="A"
filed3="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB                                         "
field4="1234567890      "
newline="\n"

我已经编写了下面的函数,它接受 file1.dml 和 file2.dat 并生成确切的结果,但我想使用 AWK 简化它,提前感谢任何帮助

function myfunc1
{
        if [ $1 == "" -a $2 == "" -a ! -f $1 -a ! -f $2 ]; then
                print "Input files not present"
        else


                dml_file=$1   #input parameter, dml file
                cntl_file=$2  #input parametr, dat file

                start_pos=1
                end_pos=0

                cat "$dml_file" | sed '1d' | sed '$d' | while IFS= read line
                do
                        counter=`echo $line | cut -d'(' -f2 | cut -d')' -f1`
                        fld_name=`echo $line | cut -d'(' -f2 | cut -d')' -f2 | sed 's/;//g'`
                        #check decimal or not
                        if [[ $counter == +([0-9]) ]]; then
                                end_pos=$((counter+start_pos))
                        else
                                counter1=`echo $counter | cut -d'.' -f1`
                                counter=$counter1
                                end_pos=$((counter1+end_pos))
                        fi
                        newline_check=`echo $fld_name | grep -i 'newline' | wc -l`
                        if [ $newline_check -gt 0 ]; then
                                fld_name="newline"
                                fld_val="\n"
                                #write below line in one file
                                echo "$fld_name : \"$fld_val\""
                        else
                                fld_val=`cat $cntl_file | cut -c$start_pos-$end_pos`
                                #write below line in one file
                                echo "$fld_name : \"$fld_val\""
                        fi

                        start_pos=$((start_pos+counter))
                done
        fi
}                                                                          

【问题讨论】:

  • 到目前为止您尝试过什么:使用awkfile2.dat 是否总是被限制为一行 file1.dat 是否有多个 start/end 块,如果是这样,输出应该是什么样子?我读对了吗...您想忽略field4scale/.2 部分吗?
  • 使用 AWK 我能够获取字段名称和长度,到目前为止没有别的。 file2.dat 将始终是单行。总会有一个从第一行开始,到最后一行结束。 scale 16.2 表示,数据长度只有 16,scale 2 可以忽略。

标签: linux bash shell unix ksh


【解决方案1】:

由于file2.dat 只有一行,我首先将其读入一个变量,这样我们就不必不断扫描文件;例如:

$ IFS= read -r rawdata < file2.dat     # 'IFS=' needed in order to retain trailing white space
$ echo ".${rawdata}."                  # periods included to show that trailing white space retained
.12345678        ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB                                          1234567890      .

此时我们可以将rawdata 变量传递给awk 解决方案:

awk -v rd="${rawdata}" -F'[();=]' '

BEGIN { s = 1 ; nl = "\\n" }

/start|end/     { next }

/newline/       { gsub(/ /,"",$4)
                  nl = $4
                  next
                }

                { split($2,a,".")
                  len = a[1]

                  gsub(/ /,"",$3)
                  fname = $3

                  printf "%s=\"%s\"\n", fname, substr(rd,s,len)
                  s += len
                }

END   { printf "newline=%s\n", nl }
' file1.dat

地点:

  • -v rd="${rawdata}" - 将awk 变量rd 定义为包含${rawdata} 的当前值
  • -F '[();=]' - 定义 4 个不同的输入/字段分隔符(();=); $2=字段长度,$3=字段名称,$4=换行符
  • BEGIN ( s = 1 ; nl= "\\n" } - 在 rd 中初始化我们的 start 位置和默认的 newline 字符 (\n)
  • /start|end/ { next } - 忽略包含 startend 的行
  • /newline/ .... - 如果我们看到 newline 模式,则删除空格并将 nl 设置为这个新值 ($4)
  • next - 停止处理当前行并转到下一行输入
  • 注意:对于我们输入文件中的其余行:
  • split($2,a,".") / len = a[1] - 根据句点分隔符将“长度”字段 ($2) 拆分为数组 a,然后将 len 设置为数组 a 的第一个元素
  • gsub(/ /,"",$3) / fname = $3 - 从字段名称 ($3) 中删除空格并将结果值分配给局部变量 fname
  • printf ... - 输出我们的数据行;使用 slenrd 中提取所需的子字符串
  • s += len - 将当前的len 添加到s 以获得新的start 位置,以便下次通过逻辑
  • END ... - 完成所有输入处理后,将我们的 newline 记录打印到标准输出

运行上述生成以下内容:

field1="12345678        "
filed2="A"
filed3="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB                                          "
field4="1234567890      "
newline="\n"

【讨论】:

  • 这解决了我的问题,感谢您为每一行提供 cmets。对理解有很大帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-04
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 2014-11-21
  • 2011-03-13
相关资源
最近更新 更多