降低UNIX Shell脚本复杂性的最佳实践

时间:2015-05-25 12:25:56

标签: shell unix

我有一个包含太多模块的脚本。该脚本运行正常,但唯一的问题是它花费了太多时间,我需要降低脚本的复杂性。

正在做什么脚本: -

我有一个源文件(它可以有多行数据,每列用'|'分隔)。

我的脚本应该检查所有列的所有行,并找到包含不正确数据的列。 (例如,非空列中的 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

期待回复。

1 个答案:

答案 0 :(得分:2)

此问题更适合this example这样的网站。

主要问题是您正在为源文件的每一行读取主文件。完全没必要。您应该阅读一次,存储其信息,然后循环遍历源文件。解决这个问题,你会看到明显的改进。

但是,如果性能是主要问题,那么shell就是错误的工具。您正在对awkcutexpr等外部工具进行多次调用。 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