从一个文件中查找字段长度并从另一个定长文件中提取相同长度的数据并将字段和数据存储在新文件中

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

我有一个文件 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 [  == "" -a  == "" -a ! -f  -a ! -f  ]; then
                print "Input files not present"
        else


                dml_file=   #input parameter, dml file
                cntl_file=  #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
}                                                                          

因为 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(/ /,"",)
                  nl = 
                  next
                }

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

                  gsub(/ /,"",)
                  fname = 

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

运行 以上生成以下内容:

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