zeile Ersetzen Sie alle Zeichen zwischen zwei Strings durch char 'X' mit sed




sed-i parameter (3)

In einem Bash-Skript versuche ich, die Zeichen zwischen zwei gegebenen Zeichenfolgen durch 'X' zu ersetzen. Ich habe paar Strings, zwischen denen ich den Ersatz von Zeichen durch 'X' passieren soll.
In dem folgenden Code wird die erste Zeichenfolge in dem Paar in cpi_list- Array deklariert. Die zweite Zeichenfolge im Paar ist immer entweder %26 oder & oder ENDOFLINE

Das mache ich.

# 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

Die Eingabe

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

Ich will es schaffen

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

PS: Der letzte %26Name%3dCOTT muss auch %26Name%3dCOTT in %26Name%3dXXXX , obwohl es kein Ende %26 weil ich entweder nach %26 als Endpunkt oder nach END OF THE LINE %26Name%3dXXXX

Aber irgendwie funktioniert es nicht.


Dies funktioniert in jedem awk, das von einer beliebigen Shell in einer UNIX-Installation aufgerufen wird:

$ 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

Genau wie bei einer sed-Substitution müsste jedes Regexp-Metazeichen in den Anfangs- und Endzeichenfolgen maskiert werden, oder wir müssten eine Schleife mit index() s anstelle von match() damit wir String-Matching statt Regexp durchführen passend.


Es ist nicht schön, aber Sie können Perl verwenden:

$ 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

Das ist für zwei Paare wie das Beispiel. N Paare in einer Linie werden eine geringfügige Änderung sein.


Sie können %26 dabei vermeiden:

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;'

Beachten Sie, dass jedes codierte Zeichen %xx für ein X zählt.





sed