从一个文件中查找字段长度并从另一个定长文件中提取相同长度的数据并将字段和数据存储在新文件中
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 }
- 忽略包含 start
或 end
的行
/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 ...
——输出我们这行数据;使用 s
和 len
从 rd
中提取所需的子字符串
s += len
- 将当前 len
添加到 s
以获得新的 s
起始位置,用于下一次通过逻辑
END ...
- 完成所有输入处理后,将我们的 newline
记录打印到标准输出
运行 以上生成以下内容:
field1="12345678 "
filed2="A"
filed3="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB "
field4="1234567890 "
newline="\n"
我有一个文件 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 }
- 忽略包含start
或end
的行
/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 ...
——输出我们这行数据;使用s
和len
从rd
中提取所需的子字符串
s += len
- 将当前len
添加到s
以获得新的s
起始位置,用于下一次通过逻辑END ...
- 完成所有输入处理后,将我们的newline
记录打印到标准输出
运行 以上生成以下内容:
field1="12345678 "
filed2="A"
filed3="BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB "
field4="1234567890 "
newline="\n"