我们有一个名为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}}
先谢谢
答案 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