我有一个包含太多模块的脚本。该脚本运行正常,但唯一的问题是它花费了太多时间,我需要降低脚本的复杂性。
正在做什么脚本: -
我有一个源文件(它可以有多行数据,每列用'|'分隔)。
我的脚本应该检查所有列的所有行,并找到包含不正确数据的列。 (例如,非空列中的 Null ,非空格列中的空间,字母表中的字段,和任何列值不是该列的有效值)。
现在我有一个主文件,它有源列表中的那些列名和该列的并置位置,并带有一些指示符,这些指示符将决定我们必须在该列上执行的操作。
,例如,主文件 -
MBR_SRC_SYS,15,H,N,N,N,1,FAC|NSC|WGS|ACE|CS9|CHP
CDH_AMT,27,H,1,1,1,N,N
以上是mater文件的示例。所以我的源文件中的15列将是MBR_SRC_SYS并且'H'表示我必须执行HARD ERROR Check。稍后是其他检查的指示符,如非空,非空格,数字格式和有效值,最后一个包含此特定列可以具有的有效值。
主文件格式 -
Clm Name,Position,HardErrorCheck,NullCheck,SpaceCheck,NumberCheck,ValidValueCheck,ValidValues
例如源文件 -
DTL|CLM| |RMB_CLM_2015_V01|RMBFCSNSC|15135NSC|rmb_fcsdmsclm_n.dat|rmb_fcsdmsclm_n.trg|NSC 2015093QA01109920150514 4 3132PD|WFS|2015093QA011099|2015/05/14 04:31:32|131|99|NAP||27002|6MB09| | |2014/10/04 00:00:00|2015/05/15 00:00:00|2015/05/15 00:00:00|2015/05/15 00:00:00|2015/05/15 00:00:00|97.26|0.00|0.00|0.00|0.00|0.00|0.00|0.00|0.00|0.00|0.00|0.00|0|0|WIFE |A|SMITH |603T40775 |270022222 |603T40775 |20 |F|1966/12/02 00:00:00|SUB|MD|SN|G2001|NTINCR|MFFFF| |91|91| |NSC|NAIIH11X|H| | | | | | | | | | | | |2015/05/15 00:00:00| | | | | | | | | | | | | | |W|D|N|P|PF|OP|N|CHK|0001025000| 7021693440|351159676 |Y| |I~IN~ ~ ~ ~ | ~ ~ | | | | | | | | |0.00|0.00|0.00| | | | | | | | | | | | | | | | |
所以,我正在做的是有2个while循环。有一个循环,我正在读取源文件的行。现在在读取后的while循环中我有另一个while循环来读取主文件并进行所有必要的检查。
假设我的源文件有500个记录,其中有100列。总循环次数将为500 * 100 = 50000 Itterations。这太多了,因为我的源文件可以有5百万的记录。
我是Unix新手,所以我不确定,但像PHP这样的脚本语言有一个超时,肯定无法运行这么久。那么应该解决这个问题呢?
以下是我的完整代码 -
#Log file creation
#exec 1> $CODE/WCC_FOA_RMBHUB/logs/RMB_HARD_ERROR_CHECK_ROWMAJOR_$(date +"%Y%m%d_%H%M%S").log 2>&1
SrcFilePath=$PMDIR/SrcFiles/WCC_FOA_RMBHUB
ListFilePath=$CODE/WCC_FOA_RMBHUB/lists
SrcFileName=$1
HardErrorFile=HARD_ERR_RMB_TEST_FILE.dat
MasterFile=$2
NullCheck()
{
value="$1"
if [ ! -n "$value" ] ; then
return 10
else
return 1
fi
}
SpaceCheck()
{
value="$1"
NullCheck "$value"
t=$?
if [ "$t" != "10" ]; then
value=$(echo $value)
if [ ! -z "$value" -a "$value" != " " ]; then
return 1
else
return 10
fi
else
return 1
fi
}
NumberCheck()
{
value="$1"
if [ $value -eq $value 2>/dev/null ]; then
return 1
else
return 10
fi
}
ValidCheck()
{
value="$1"
# Replace space with 'SPACE'
SpaceCheck "$value"
t1=$?
if [ "$t1" == "10" ]; then
value="SPACE"
fi
ValidFromMapping="$2"
needle="|"
NumberOfDelimeter=$(echo $ValidFromMapping | awk 'BEGIN{FS="|"} {print NF}')
v=1
vf=0
while [ $NumberOfDelimeter -gt 0 ]
do
#echo YES
ValidValue=$(echo "$ValidFromMapping" | cut -d'|' -f$v)
#echo "Checking with the value $ValidValue."
if [ "$ValidValue" == "$value" ]; then
vf=1
fi
v=$(expr $v + 1)
NumberOfDelimeter=$(expr $NumberOfDelimeter - 1)
done
if [ $vf -eq 1 ]; then
#echo "Match Found"
return 1
else
#echo "No Match Found"
return 10
fi
}
SoftErrThreshHold=0
#echo "Errrr... We got a hard error check column. We have to check $ColumnName in the whole god dam source table. This column is available in column $ColNum .We got to do it brah !!!\n"
while read RowOne
do
HardErrorFlag=1
SoftErrorFlag=1
RecordColumn=$(echo "$RowOne" | cut -d'|' -f1)
#echo "Started New Row"
if [ "$RecordColumn" == "DTL" ]; then
KeyColumn=$(echo "$RowOne" | cut -d'|' -f9)
ErrorText="$KeyColumn |HARD ERROR OCCURRED IN THE FOLLOWING COLUMN(S):"
SoftErrorText="$KeyColumn |SOFT ERROR OCCURRED IN THE FOLLOWING COLUMN(S):"
while read line
do
ColumnName=`echo $line | cut -d',' -f1`
ColNum=`echo $line | cut -d',' -f2`
ErrorCheck=`echo $line | cut -d',' -f3`
NullCheckStatus=`echo $line | cut -d',' -f4`
SpaceCheckStatus=`echo $line | cut -d',' -f5`
NumberCheckStatus=`echo $line | cut -d',' -f6`
ValidCheckStatus=`echo $line | cut -d',' -f7`
ValidValues=`echo $line | cut -d',' -f8`
# Hard Error Check -
if [ "$ErrorCheck" == "H" ]; then
#echo "Doing Hard Error"
IsNull=1;
IsNumber=1;
IsSpace=1;
IsValid=1;
HardErrorCheckColumnValue=$(echo "$RowOne" | cut -d'|' -f$ColNum)
#echo "Value is $HardErrorCheckColumnValue."
#Funtions Return 10 if it is NULL/SPACE/NOT A NUMBER
#echo $NullCheckStatus
if [ "$NullCheckStatus" == "1" ]; then
NullCheck "$HardErrorCheckColumnValue"
IsNull=$?
fi
#echo $NumberCheckStatus
if [ "$NumberCheckStatus" == "1" ]; then
NumberCheck "$HardErrorCheckColumnValue"
IsNumber=$?
NullCheck "$HardErrorCheckColumnValue"
IsNull=$?
SpaceCheck "$HardErrorCheckColumnValue"
IsSpace=$?
fi
#echo $SpaceCheckStatus
if [ "$SpaceCheckStatus" == "1" ]; then
SpaceCheck "$HardErrorCheckColumnValue"
IsSpace=$?
fi
#echo $ValidCheckStatus
if [ "$ValidCheckStatus" == "1" ]; then
ValidCheck "$HardErrorCheckColumnValue" "$ValidValues"
IsValid=$?
fi
if [ $IsNull -eq 10 ] || [ $IsNumber -eq 10 ] || [ $IsSpace -eq 10 ] || [ $IsValid -eq 10 ]; then
HardErrorFlag=10
if [ $IsNull -eq 10 ]; then
ErrorText=$ErrorText" $ColumnName is Null or Invalid; "
fi
if [ $IsNumber -eq 10 ]; then
ErrorText=$ErrorText" $ColumnName is not a valid number; "
fi
if [ $IsSpace -eq 10 ]; then
ErrorText=$ErrorText" $ColumnName is Space or Invalid; "
fi
if [ $IsValid -eq 10 ]; then
ErrorText=$ErrorText" $ColumnName is not a valid value; "
fi
fi
fi
# Soft Error Check -
if [ "$ErrorCheck" == "S" ]; then
#echo "Doing Soft Error"
IsSValid=1
IsSNull=1;
IsSNumber=1;
IsSSpace=1;
SoftErrorCheckColumnValue=$(echo "$RowOne" | cut -d'|' -f$ColNum)
#echo "Value is $SoftErrorCheckColumnValue."
#Funtions Return 10 if it is NULL/SPACE/NOT A NUMBER
#echo $NullCheckStatus
if [ "$NullCheckStatus" == "1" ]; then
NullCheck "$SoftErrorCheckColumnValue"
IsSNull=$?
fi
#echo $NumberCheckStatus
if [ "$NumberCheckStatus" == "1" ]; then
NumberCheck "$SoftErrorCheckColumnValue"
IsSNumber=$?
NullCheck "$SoftErrorCheckColumnValue"
IsSNull=$?
SpaceCheck "$SoftErrorCheckColumnValue"
IsSSpace=$?
fi
#echo $SpaceCheckStatus
if [ "$SpaceCheckStatus" == "1" ]; then
SpaceCheck "$SoftErrorCheckColumnValue"
IsSpace=$?
fi
#echo $ValidCheckStatus
if [ "$ValidCheckStatus" == "1" ]; then
ValidCheck "$SoftErrorCheckColumnValue" "$ValidValues"
IsSValid=$?
fi
if [ $IsSNull -eq 10 ] || [ $IsSNumber -eq 10 ] || [ $IsSSpace -eq 10 ] || [ $IsSValid -eq 10 ]; then
SoftErrorFlag=10
if [ $IsSNull -eq 10 ]; then
SoftErrorText=$SoftErrorText" $ColumnName is Null or Invalid; "
fi
if [ $IsSNumber -eq 10 ]; then
SoftErrorText=$SoftErrorText" $ColumnName is not a valid number; "
fi
if [ $IsSSpace -eq 10 ]; then
SoftErrorText=$SoftErrorText" $ColumnName is Space or Invalid; "
fi
if [ $IsSValid -eq 10 ]; then
SoftErrorText=$SoftErrorText" $ColumnName is not a valid value; "
fi
SoftErrThreshHold=$(expr $SoftErrThreshHold + 1)
fi
fi
done <$ListFilePath/$MasterFile
if [ $HardErrorFlag -eq 10 ]; then
echo $ErrorText
fi
if [ $SoftErrorFlag -eq 10 ]; then
echo $SoftErrorText
fi
fi
done <$SrcFilePath/$SrcFileName
if [ $SoftErrThreshHold -eq 0 ]; then
echo "No Soft Error was found in the file"
else
echo "Total Count Of SofErrors Found : $SoftErrThreshHold"
fi
期待回复。
答案 0 :(得分:2)
此问题更适合this example这样的网站。
主要问题是您正在为源文件的每一行读取主文件。完全没必要。您应该阅读一次,存储其信息,然后循环遍历源文件。解决这个问题,你会看到明显的改进。
但是,如果性能是主要问题,那么shell就是错误的工具。您正在对awk
,cut
,expr
等外部工具进行多次调用。 shell可以进行算术运算并在分隔符上拆分字符串。我会为awk或perl重写整个事情,它具有你需要的所有文本处理功能,然后我花了很多时间试图让shell程序更有效率。
特定的shell改进:在逗号上拆分字符串并保存字段:执行此操作
IFS=',' read ColumnName ColNum ErrorCheck NullCheckStatus SpaceCheckStatus NumberCheckStatus ValidCheckStatus ValidValues <<< "$line"
而不是:
ColumnName=`echo $line | cut -d',' -f1`
ColNum=`echo $line | cut -d',' -f2`
ErrorCheck=`echo $line | cut -d',' -f3`
NullCheckStatus=`echo $line | cut -d',' -f4`
SpaceCheckStatus=`echo $line | cut -d',' -f5`
NumberCheckStatus=`echo $line | cut -d',' -f6`
ValidCheckStatus=`echo $line | cut -d',' -f7`
ValidValues=`echo $line | cut -d',' -f8`
如何阅读主文件:
# not strictly necessary: declare some array variables
declare -a colname errchk nullchk spacechk numchk validchk values
while IFS=',' read -r ColumnName ColNum ErrorCheck NullCheck SpaceCheck NumberCheck ValidCheck ValidValues
do
colname[$ColNum]=$ColumnName
errchk[$ColNum]=$ErrorCheck
nullchk[$ColNum]=$NullCheck
spacechk[$ColNum]=$SpaceCheck
numchk[$ColNum]=$NumberCheck
validchk[$ColNum]=$ValidCheck
values[$ColNum]=$ValidValues
done < MasterFile
然后阅读源文件:
while IFS='|' read -ra fields; do
for (( i=0; i < ${#fields[@]}; i++ )); do
if [[ -n ${colname[$i]} ]]; then
# there was an entry for this column number in the Master file
# perform your checks for column number $i
# the column value is "${fields[$i]}"
fi
done
# check your hard/soft error flags here
done < SourceFile