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

问题描述 投票:0回答:1

我有一个文件file1.dml和另一个固定长度的数据文件file2.dat.data在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
}                                                                          
linux bash shell unix ksh
1个回答
0
投票

因为 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" } - 初始化 s挞位 rd 和一个默认的 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 ... - 输出我们的数据线;使用 slen 中提取所需的子串。rd
  • s += len - 添加当前 lens 焕然一新 s挞位
  • END ... - 当所有输入处理完成后,打印我们的 newline 录入到stdout

运行上述内容会产生以下结果。

field1="12345678        "
filed2="A"
filed3="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB                                          "
field4="1234567890      "
newline="\n"
© www.soinside.com 2019 - 2024. All rights reserved.