Substitua todas as letras de uma palavra por '*' depois de uma determinada palavra em um arquivo de texto

3

Eu preciso criar um script que substitua todas as letras de uma palavra após uma determinada palavra por um asterisco ( * ). Por exemplo:

sed 's/Word:[^ ]\+/Word:*/' Desktop/script_test

Mas este script substitui a palavra inteira por apenas um asterisco, enquanto eu quero substituir todas as letras. Como eu posso fazer isso? Por exemplo, com esta entrada:

Word: cat

Eu quero pegar

Word: ***

Estou executando o Linux.

P.S. A entrada deve ser lida de um arquivo de texto e também salva no mesmo arquivo.

    
por Replace 21.02.2017 / 08:48

9 respostas

4

Você pode fazer isso de uma vez em um loop:

sed -e :1 -e 's/\(Word: *[^ ]*\)[^ *]/*/;t1'

Para editar o arquivo no lugar e assumindo que todos os caracteres para substituir são de byte único, você pode fazer o stdin do sed e stdout o arquivo como em:

sed ... < file 1<> file

Ou com o GNU sed, use o sinalizador -i como em:

sed -i ... file

(Embora isso substitua o arquivo por um novo (embora com o mesmo nome). Com o BSD sed, use -i '' em vez de -i ).

    
por 21.02.2017 / 17:02
3

Que tal:

$ cat file
Word: cat
Word: foobar
$ sed -E 's/Word: *//; s/./*/g; s/^/Word: /' file
Word: ***
Word: ******

Para modificar o arquivo, use apenas -i :

$ sed -E -i 's/Word: *//; s/./*/g; s/^/Word: /' file

Observe que isso não funcionará se Word: não for a primeira palavra da linha. Se isso é um problema, você pode usar isso:

perl -pe 's/Word:\s*\K(\S+)/sprintf "*" x length($1)/e' file

Isso, por sua vez, pressupõe que você deseja o primeiro Word: em cada linha e também que deseja que tudo seja substituído por * . Se você quer apenas que a primeira palavra depois de Word: seja substituída, você realmente deveria fazer uma nova pergunta ou, pelo menos, esclarecer esta.

    
por 21.02.2017 / 10:42
1

Você poderia fazer isso usando sed da seguinte forma:

echo 'Word: cat' |
sed -e '
   s/Word:/&\n/
   :loop
      s/\n\([^a-zA-Z]*\)[a-zA-Z]/*\n/
   tloop
   s/\n\([^a-zA-Z]*\)$//
' 
    
por 21.02.2017 / 10:40
1

Você pode usar esse tempo usando o espaço de espera para manipulações, como:

sed -e '
   s/Word:/&\n/   # everything to the right of marker is asterisk zone
   h              # will need later on for reconstructing, so save orig
   s/.*\n//       # retain only the asterisk zone
   s/[a-zA-Z]/*/g # perform the asterisk operation
   H;g            # abut onto original data
   s/\n.*\n//     # peel off unwanted data
'
    
por 21.02.2017 / 10:56
1

Perl

echo 'Word: cat' |
perl -lpe '
   1 while s/(?<=Word:)([^a-zA-Z]*)([a-zA-Z]+)/$1 . "*" x length($2)/e;
'

Bash

eval "'echo 'NL=qsq' | tr 'qs' '72''"; # newline
echo 'Word: cat' |
while IFS= read -r line
do
   var=${line/Word:/Word:"$NL"}
   var1=${var#*"$NL"}     var2=${var%"$NL"*}
   var3=${var1//[a-zA-Z]/*}
   var4=${var2}${var3}
   printf '%s\n' "$line" "$var4"
done
    
por 21.02.2017 / 12:46
1

Solução Python com argumentos de linha de comando mais flexíveis:

#!/usr/bin/env python3
import sys, fileinput

def replace_after(haystack, needle, replacement):
    pos = haystack.find(needle)
    if pos >= 0:
        pos += len(needle)
        return haystack[:pos] + (replacement * (len(haystack) - pos))
    else:
        return haystack

if __name__ == '__main__':
    needle, replacement = sys.argv[1:3]
    del sys.argv[1:3]

    with fileinput.input() as finput:
        for line in finput:
            print(replace_after(line.rstrip('\n'), needle, replacement))

Uso:

python3 unix.se.346510.py <NEEDLE> <REPLACEMENT> [FILES...]

Exemplo:

$ printf '%s\n' 'Word: foo' 'more Word: bar-baz' | python3 unix.se.346510.py 'Word: ' '*'
Word: ***
more Word: *******
    
por 21.02.2017 / 13:52
1

Uma solução awk e uma solução shell:

echo '"Hello: World"' | awk '{ gsub("[^\"]", "*", $2); print }'

Precisamos escapar do " em [^\"] , pois a própria expressão regular está entre aspas duplas. Isso gera

"Hello: *****"

Com o shell (pelo menos bash e ksh93 ):

echo '"Hello: World"' | {
  read -r prefix rest
  printf '%s %s\n' "$prefix" "${rest//[^\"]/*}"
}

Supondo que o texto "Hello: World" esteja em uma linha própria, mas incorporado em um texto maior no arquivo greetings.txt :

awk '/"Hello: [^"]*"/ { gsub("[^\"]", "*", $2) } { print }' greetings.txt >greet.tmp && mv greet.tmp greeting.txt

ou (novamente, com bash ou ksh93 ),

while read -r prefix rest; do
    if [[ "$prefix" =~ ^\"Hello: ]]; then
        rest=${rest//[^\"]/*}
    fi
    printf '%s %s\n' "$prefix" "$rest"
done <greetings.txt >greet.tmp
mv greet.tmp greetings.txt

Para a entrada

Specific recipients:
"Hello: Mom!"
"Hello: Cat!"

General recipients:
"Hello: World!"

essas duas soluções geram

Specific recipients:
"Hello: ****"
"Hello: ****"

General recipients:
"Hello: ******"
    
por 21.02.2017 / 10:26
1

Coisas assim melhoram com o flex:

%option 8bit main
%s star
%%
Word:           ECHO;  BEGIN star;
<star>[^ \t\n]+ memset(yytext,'*',yyleng); ECHO; BEGIN 0;

coloque em star.l e make star .

(editar: estados são um grande exagero para isso. melhor:

%option 8bit main
%%
Word:[^ \t\n]* memset(yytext+5,'*',yyleng-5); ECHO;

    
por 21.02.2017 / 17:52
0

Usando o awk, você não menciona o uso específico de sed:)

echo "Word: cat" | awk '{printf $1" "; for (i=1;i<=length($2);i++) printf "*"}'

Resultado:

Word: ***

    
por 21.02.2017 / 09:39