unix.Script中的性能调整非常慢

时间:2018-06-05 15:16:28

标签: unix awk sed

我们有一个名为data_mask的函数。它接受字符串并掩盖它。在我们的文件中,我们希望根据用户给出的输入屏蔽任何列。为此,我们将文件列分成3部分。

 pre_str=`echo $p | cut -d'|' -f1-$((colnum - 1))`
    column_value=`echo $p | cut -d'|' -f$colnum`
    post_str=`echo $p | cut -d'|' -f$((colnum + 1))-$totalcol`
    echo "column_value=$column_value"
     maskvalue=$(data_mask "$column_value")
    echo $pre_str"|"$maskvalue"|"$post_str >> $outputfile

这里colnum是我们通过传递user输入的列值调用的user.data_mask函数输入的数字。 假设用户输入5,则pre_str将存储1到4的列.column_value将存储需要屏蔽的列。 post_str将在隐藏列之后存储该列。这里我们分割列值然后连接它。任何更好的方法来做到这一点。这需要很多时间。

我们可以通过awk或sed更改以下行吗?我们正在分割每行并逐行读取数据。

11|Shrut|consultant
12|wipro|company
13|capgemini|IT

以下是示例输入: -

11|sqmbr|consultant
12|itzaw|company
13|khvlipkoi|IT

如果用户输入2则输出应为

data_mask() {

  col_val=$1
  l_ret_str=""
  l_an=0
  l_lp=0
  l_mod=0
  absnum=0
  austart=65
  auend=90
  aclsize=26
  alstart=97
  alend=122
  nstart=48
  nend=57
  nclsize=10

  l_lp=`expr length "$col_val"`
  if [[ $l_lp -ne 0 ]]; then
    for i in `eval "echo {1..$l_lp}"`
    do
      single_char=$(SUBSTR "$col_val" $i)
      ascii_num_val=$(ASCII "$single_char")
      l_mod=$((l_mod+ascii_num_val))
    done

    l_mod=$((l_mod % nclsize))

    for i in `eval "echo {1..$l_lp}"`
    do
      single_char=$(SUBSTR "$col_val" $i)
      ascii_num_val=$(ASCII "$single_char")
      l_an=$ascii_num_val
      tempvar=$((l_an - l_lp - l_mod - i))
      absnum=$(ABS $tempvar)
      if [[ $l_an -ge $austart && $l_an -le $auend ]]; then
        tempmodval=$((absnum % aclsize))
        tempasciival=$((austart + tempmodval))
        l_ret_str=$l_ret_str$(CHR $tempasciival)
      elif [[ $l_an -ge $alstart && $l_an -le $alend ]]; then
        tempmodval=$((absnum % aclsize))
        tempasciival=$((alstart + tempmodval))
        l_ret_str=$l_ret_str$(CHR $tempasciival)
      elif [[ $l_an -ge $nstart && $l_an -le $nend ]]; then
        tempmodval=$((absnum % nclsize))
        tempasciival=$((nstart + tempmodval))
        l_ret_str=$l_ret_str$(CHR $tempasciival)
      else
        tempmodval=$((absnum % nclsize))
        tempasciival=$((austart + tempmodval))
        l_ret_str=$l_ret_str$(CHR $tempasciival)
      fi

    done
  fi
  echo "$l_ret_str"
}

屏蔽算法写在函数data_mask中。我们只需要更改上面的代码。 下面是我们的data_mask函数。

{{1}}

先谢谢

3 个答案:

答案 0 :(得分:1)

听起来这就是你要找的东西:

$ cat tst.sh
data_mask() { printf '%s\n' "${1//?/_}"; }

col="$1"
file="$2"
skip=2

sep='|'
tail +"$(( skip + 1 ))" "$file" |
cut -f "$col" -d "$sep" |
while IFS= read -r val; do
    data_mask "$val"
done |
awk -F"$sep" -v OFS="$sep" -v col="$col" -v skip="$skip" '
    NR==FNR { a[NR]=$0; next }
    FNR > skip { $col = a[FNR-skip] }
    { print }
' - "$file"

我的data_mask()只是将每个字符转换为下划线 - 显然用你的真实函数替换它。

如前所述,如果你在awk中重写data_mask()(看起来这是一项微不足道的任务),那么其余部分也可以完全用awk完成,然后执行速度将提升100倍。

答案 1 :(得分:0)

我将输出重定向移动到循环外部。还要将数据读入数组,只需将所选列替换为“inline”

(   # run loop in a subshell so changing IFS does not affect rest of script
    IFS='|'
    while read -ra fields; do
        if (( line > skip_line )); then
            # subtract 1 since bash arrays are indexed starting from 0
            fields[colnum-1]=$(data_mask "${fields[colnum-1]}")
        fi
        echo "${fields[*]}"   # this will use $IFS to join the fields.
        ((line++))
    done <"$temp_outputfile" >"$outputfile"
)

如果有的话,这可能不会大大提高性能。鉴于您正在读取“临时”文件,我怀疑您的磁盘IO数量超出了必要的数量。

Perl通常比bash快很多,但我不打算为你翻译代码。

答案 2 :(得分:0)

上周我在awk写了一个类似的功能。它很快疯狂,很好地完成了工作。

function smartmatch(diamond, rough,   x, y) {
  for (x in rough) y[rough[x]]
  return diamond in y
}
function getrandchar(){
        charlist="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        return substr(charlist, int(rand()*51+1), 1);
}    
BEGIN{
        srand();
        split(fieldstr,fieldarr,",");
        OFS=FS;
}

#preserve the header if requested
header==1 && NR==1 {
        print $0;
}

header==1 && NR>1 || header==0{

        #loop through columns   
        for (i=1;i<=NF;i++){

                #check if this is a field we are scrambling
                if (smartmatch(i,fieldarr)){                      

                        #iterate through each character
                        for (j=1;j<=length($i);j++){

                                #if it's numeric then pick a random digit
                                if (substr($i,j,1) ~ /[0-9]/){
                                        printf "%s", int(10*rand());

                                #if it's not an alpha hen just print it
                                }else if(substr($i,j,1) ~ /[^a-zA-Z]/){
                                        printf "%s", substr($i,j,1);

                                #must be an alpha, generate a random character
                                }else{
                                        printf "%s", getrandchar();                                         
                                }
                        }

                        #complete the field
                        printf "%s", i!=NF ? OFS : "";
                }else{
                        #complete the line
                        printf "%s%s", $i, i!=NF ? OFS : "";
                }

        }
        printf "\n"
}

用随机数字替换数字,用随机字母(大写或小写)替换字母。它还保留特殊字符(不在a-zA-Z中的字符)。

保存data_mask.awk您可以像以下一样使用它:

 awk -v header="1" -v fieldstr="4,5,6" -f data_mask.awk your_file_here

header="1"告诉它有一个标题并保留它。 fieldstr="4,5,6"告诉它掩盖这些列。

与任何awk脚本一样,当您使用-F标志调用它时,可以告诉它列分隔符,如管道分隔数据的-F"|"

示例:

echo "this,is,a,test,567-harry,anemail@example.com" | awk -F"," -v header="0" -v fieldstr="4,5,6" -f data_mask.awk
this,is,a,vtKC,002-DOrpu,YFabCKk@pBwFXnl.Wjc