2017-01-30 2 views
-2

В сценарии Bash я пытаюсь вставить в файл замену символов между двумя заданными строками на 'X'. У меня есть группа строк, между которыми я хочу заменить символы на «X».
В приведенном ниже коде строка в паре объявляется в cpi_list массив. второй строка в паре всегда либо %26 или & или ENDOFLINEЗамените все символы между двумя строками символом 'X', используя sed

Это то, что я делаю.

# 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

Но почему-то это не работает.

+0

Какой результат * вы получаете? – chepner

+0

% 3dCOTT, потому что он находится между% 26Name% 3d и концом строки. –

+0

@chepner Этот результат я получаю 'CPI.% 26Name% 3dXXXXXXXXXXXXXXXXXXXX% 26Name% 3dCOTT' –

ответ

3

Это будет работать в любом AWK вызывается из любой оболочки в любой установке UNIX:

$ 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, любой метасимвол регулярного выражения в начале и конце строки должен быть экранирован или нам нужно будет использовать цикл h index() s вместо match(), поэтому вместо соответствия регулярному выражению мы будем сопоставлять строки.

+0

Спасибо Ed .. Однако я заметил, что '% 26Pwd% 3dBOTTLE% 26' не изменяется на'% 26Pwd% 3dXXXXXX% 26' –

+0

О, я думаю, что я не объяснил это правильно .. '% 26Name% 3d' и'% 26Pwd% 3d' - это две первые строки или начальная строка .. конечная строка всегда '% Или конец строки. Поэтому мне нужно заменить символы между '% 26Name% 3d' и'% 26' .. между '% 26Pwd% 3d' и'% 26' .. между '% 26Name% 3d' и' END OF LINE' ... . как это. –

+0

Привет Ed .. Я обновил исходный текст вопроса, чтобы дать больше разъяснений. –

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 пар в строке будет небольшой модификацией.

+0

К сожалению, я должен сделать это в сценарии bash. Не перл. –

+1

Почему вы «имеете» сделать это в «bash»? – chepner

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.

+0

GNU sed только. POSIX потребуется изменение. – dawg

+0

@dawg: что-то вроде этого, я полагаю: 'sed -e 's /% 26/\ &/g;' -e: a -e '/ \ (% 3d [^ &] * \) [^ & X]/\ 1X/g; ta; s/& /% 26/g; ''(я использую только GNU sed) –

+0

Это не работает, потому что пространство шаблонов' a' локально привязано к каждому '-e' – dawg

Смежные вопросы