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

unix.Script中的性能调优非常慢,unix,awk,sed,Unix,Awk,Sed,我们有一个名为data_mask的函数。它接受字符串并屏蔽它。在我们的文件中,我们希望根据用户提供的输入屏蔽任何列。为此,我们将文件的列分为3部分 while read p; do if [[ $line -le $skip_line ]]; then echo "$p" >> $outputfile else pre_str=`echo $p | cut -d'|' -f1-$((colnum - 1))` column_value=`echo $

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

while read p; do

  if [[ $line -le $skip_line ]]; then
    echo "$p" >> $outputfile
  else
    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


  fi

  line=$((line + 1))

  done <$temp_outputfile
以下是示例输入:-

11|Shrut|consultant
12|wipro|company
13|capgemini|IT
如果用户输入2,则输出应为

11|sqmbr|consultant
12|itzaw|company
13|khvlipkoi|IT
屏蔽算法写在函数数据屏蔽中。我们只需要更改上面的代码。 下面是我们的数据屏蔽函数

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"
}

提前感谢

我将把输出重定向移到循环的外部。同时将数据读入数组,只需替换所选列“inline”

(#在子shell中运行循环,这样更改IFS不会影响脚本的其余部分
IFS=“|”
当读取ra字段时,执行以下操作:
如果((行>跳过行));则
#减去1,因为bash数组的索引从0开始
字段[colnum-1]=$(数据掩码“${fields[colnum-1]}”)
fi
echo“${fields[*]}”#这将使用$IFS加入字段。
((line++)
完成“$outputfile”
)
这可能不会大大提高性能(如果有的话)。鉴于您正在读取一个“临时”文件,我怀疑您正在执行的磁盘IO超出了需要


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

我上周刚刚在
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"
}
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

听起来这就是你想要的:

$ 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"
My data_mask()只是将每个字符转换为下划线,显然用实际函数替换它

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"
}

如前所述,如果您在awk中重新编写data_mask()(看起来这是一项琐碎的任务),那么其余的工作也可以完全在awk中完成,然后执行速度将提高100倍。

同样的问题一再出现,似乎您没有使用给出的建议。那么,为什么还要问呢?在
bash
中使用扩展字符串操作是一种反模式。整个shebang可以通过一个简单的
awk
脚本来完成,它的性能至少比这个脚本高100倍。到底发生了什么?我们有您和另一位用户,他们都反复询问有关名为“data_mask”(请参阅)的函数的问题,忽略您得到的建议,然后请求更多帮助以继续做错误的事情,包括现在如何通过做错误的事情来解决您所遇到的明显、可预测的性能问题!接受别人给你的建议,并以此为基础。@Shrutisharma否决票不会阻止你提问。他所要做的就是提供缺失的信息,这本应该是三分之一的,但他选择不提供,因此累积了多张反对票,至少有5张来自多人的接近不清楚的票,因为没人知道他在问什么。我一点也不开玩笑,我只是想知道你需要什么。您现在一定已经注意到,您当前的提问方法不起作用,所以为什么不花一点时间简单地提供每个人都在问您的问题,这样我们就可以实际帮助您了。好的,请说“我有一个名为data_mask()的shell函数”我们不能改变并且给定输入X输出Y。我们的调用代码效率低下,我们需要改进它。”。现在添加示例输入和预期输出,展示您迄今为止所做的尝试,并寻求帮助。就这么简单。发布一个不能更改的50行函数是没有意义的,因此它不是您请求帮助的一部分,它只是让您更难确定您需要帮助的内容。很抱歉,聊天帮不上忙-我们只需要你发布一个简洁、可测试的示例输入和预期输出。当然@EdMorton。非常感谢你的善意帮助。感谢格伦宝贵的时间和帮助。我将实现同样的功能。谢谢@JNevill。谢谢你宝贵的时间和帮助。谢谢@Ed Morton。非常感谢你的帮助。我将在输出中尝试同样的方法。即使是你制作的data_mask()函数也令人惊叹。但有时我们必须倾听客户的意见。不管他们知道还是不知道,他们总是对的。非常感谢您对我们的宽容和您的善意帮助。谢谢@Ed Morton。我们感谢你的帮助。你能用脚本做些小修改吗。如果用户想跳过头n行,比如header和all,那么如何将该部分嵌入脚本中。这些行应该是输出的一部分,但不应该调用函数。OK,我更新了答案,跳过转换前2行。再说一次——如果你只是在你的问题中提供了真正有代表性的样本输入和预期输出,我们就不必来回剥洋葱皮来找出你的需求和解决方案。您的问题中的示例中没有标题,因此更新的脚本未经测试。我现在得到了。谢谢埃德·莫顿。你非常善良,乐于助人。
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
$ 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"