我有一个文件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
}
因为 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 }
- 忽略包含 start
或 end
/newline/ ....
- 如见其人 newline
然后去掉空格,设置 nl
到这个新的值 ($4
)next
- 停止当前行的处理,转入下一行的输入。split($2,a,".")
len = a[1]
- 分割 "长度 "字段($2
)为基础的周期分隔符,将其转化为数组 a
,然后设置 len
到数组的第一个元素 a
gsub(/ /,"",$3)
fname = $3
- 删除字段名中的空白 ($3
),并将所得值赋给局部变量 fname
printf ...
- 输出我们的数据线;使用 s
和 len
中提取所需的子串。rd
s += len
- 添加当前 len
到 s
焕然一新 s
挞位END ...
- 当所有输入处理完成后,打印我们的 newline
录入到stdout运行上述内容会产生以下结果。
field1="12345678 "
filed2="A"
filed3="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB "
field4="1234567890 "
newline="\n"