用char' X'替换两个字符串之间的所有字符。使用sed

时间:2017-01-30 19:34:12

标签: string bash shell awk sed

在Bash脚本中,我试图通过' X'在文件中替换两个给定字符串之间的字符。我有一堆字符串对,在这之间我希望用' X'替换字符。应该发生。
在下面的代码中,对中的第一个字符串在 cpi_list 数组中声明。对中的第二个字符串始终为 %26&ENDOFLINE

这就是我在做的事。

# list of "first" or "start" string
declare -a cpi_list=('%26Name%3d' '%26Pwd%3d')  

# This is the "end" string
myAnd=\%26
newfile="inputlog.txt"

for item in "${cpi_list[@]}";
do
    sed -i -e :a -e "s/\($item[X]*\)[^X]\(.*"$myAnd"\)/\1X\2/;ta" $newfile;
done

输入

CPI.%26Name%3dJASON%26Pwd%3dBOTTLE%26Name%3dCOTT
CPI.%26Name%3dVoorhees&machete

我想成功

CPI.%26Name%3dXXXXX%26Pwd%3dXXXXXX%26Name%3dXXXX
CPI.%26Name%3dXXXXXXXX&machete

PS:即使没有结束%26Name%3dCOTT,最后一项也需要将%26Name%3dXXXX更改为%26,因为我正在寻找%26作为终点或END OF THE LINE

但不知怎的,它不起作用。

3 个答案:

答案 0 :(得分:4)

这适用于任何UNIX安装中从任何shell调用的任何awk:

$ cat tst.awk
BEGIN {
    begs = "%26Name%3d|%26Pwd%3d"
    ends = "%26|&"
}
{
    head = ""
    tail = $0
    while( match(tail, begs) ) {
        tgtStart = RSTART + RLENGTH
        tgt = substr(tail,tgtStart)
        if ( match(tgt, ends) ) {
            tgt = substr(tgt,1,RSTART-1)
        }

        gsub(/./,"X",tgt)
        head = head substr(tail,1,tgtStart-1) tgt
        tail = substr(tail,tgtStart+length(tgt))
    }
    $0 = head tail

    print
}

$ cat file
CPI.%26Name%3dJASON%26Pwd%3dBOTTLE%26Name%3dCOTT
CPI.%26Name%3dVoorhees&machete

$ awk -f tst.awk file
CPI.%26Name%3dXXXXX%26Pwd%3dXXXXXX%26Name%3dXXXX
CPI.%26Name%3dXXXXXXXX&machete

就像使用sed替换一样,在beg和end字符串中的任何正则表达式元字符都需要被转义,或者我们必须使用index() s代替match()的循环,所以我们' d进行字符串匹配而不是正则表达式匹配。

答案 1 :(得分:0)

它不是漂亮但您可以使用perl:

$ s1="CPI.%26Name%3dJASON%26Pwd%3dBOTTLE%26Name%3dCOTT"
$ echo "$s1" | perl -lne 'if (/(?:^.*%26Name%3d)(.*)(?:%26Pwd%3d)(?:.*%26Name%3d)(.*)((?:%26Pwd%3d)|(?:$))/) { 
        $i1=$-[1];
        $l1=$+[1]-$-[1];
        $i2=$-[2];
        $l2=$+[2]-$-[2];
        substr($_, $i1, $l1, "X"x$l1);
        substr($_, $i2, $l2, "X"x$l2);
        print;
        }'
CPI.%26Name%3dXXXXX%26Pwd%3dBOTTLE%26Name%3dXXXX

这就像两对一样的例子。一行中的N对将略有修改。

答案 2 :(得分:0)

您可以避免%26这样做:

a='CPI.%26Name%3dJASON%26Pwd%3dBOTTLE%26Name%3dCOTT'
echo "$a" |sed -E ':a;s/(%3dX*)([^%X]|%[013-9a-f][0-9a-f]|%2[0-5789a-f])/\1X/g;ta;'

请注意,每个编码字符%xx计为一个X.