Substituindo um caractere em uma posição aleatória usando sed?

1

Estou tentando substituir um caractere em um arquivo em uma posição aleatória. Meu arquivo parece algo como:

aab  
babab  
abab  

Estou tentando substituir um caractere aleatório por 'c'. Então, a saída pode parecer:

aab  
bcbab  
abab 

Eu tentei remover todas as quebras de linha e salvar em um arquivo new_string.txt e depois usar sed, mas não está funcionando.

Este é o código que tentei:

rand1="$(shuf -i 0-$tot_len -n 1)"
sed "s/^\(.\{"${rand1}"\}\)./G/" new_string.txt

Continuo recebendo o erro:

sed: -e expression #1, char 25: Invalid content of \{\}
    
por user3891532 11.08.2015 / 13:51

4 respostas

1

Não há necessidade das chaves na sua variável, e a variável também deve ser citada. Use:

sed "s/^\(.\{$rand1\}\)./G/" new_string.txt

UPDATE: conforme indicado abaixo nos comentários:

O código original é bom, mas o inteiro para $rand1 é muito grande para sed . Descobri que o valor máximo pode ser 32767 para o GNU sed , ou seja, sed ainda recebe apenas inteiros de 16 bits.

Você pode obter esse limite para a biblioteca de expressões regulares do sistema (embora o GNU sed geralmente use uma versão incorporada) com:

$ getconf RE_DUP_MAX
32767

O POSIX requer que o limite seja pelo menos _POSIX_RE_DUP_MAX (255), e esse é o máximo que você pode esperar portável (alguns sistemas como o Solaris ou OS / X têm esse valor tão baixo).

    
por 11.08.2015 / 14:00
1

Em um sistema GNU, para substituir aleatoriamente um caractere (diferente de nova linha), você poderia fazer:

file=myfile.txt
offset=$(grep -bo . < "$file" | cut -d: -f1 | shuf -n1)
[ -z "$offset" ] || # file doesn't have non-newline characters
  printf c | dd bs=1 seek="$offset" of="$file" conv=notrunc status=none

(com versões antigas do GNU dd (anterior a 8.20), substitua status=none por 2> /dev/null ).

grep -bo . < "$file" fornecerá o deslocamento em número de bytes no arquivo de cada caractere não pertencente à nova linha. Por exemplo, com um arquivo codificado em UTF-8 que contém:

$3
£1
€2

Isso nos dá:

$ grep -bo . < "$file"
0:$
1:3
3:£
5:1
7:€
10:2

Com cut -d: -f1 , retemos a parte antes dos primeiros dois pontos. Então, escolhemos um desses deslocamentos aleatoriamente com shuf -n1 .

Isso pressupõe que o caractere substituto tenha o mesmo tamanho que o substituído. Por exemplo, substituir o valor acima (2 bytes) por c (1 byte) deixaria o arquivo com c seguido por um caractere inválido.

Para contornar isso, não podemos mais sobrescrever o arquivo in-loco, já que precisaríamos mudar os dados.

Precisamos de algo como:

perl -C -0777 -pi -e "substr \$_, $offset, 1, 'c'" -- "$file"

em vez disso. Com -C , perl respeita a localidade para o que constitui um caractere . -0777 -p ativa o modo slurp , em que o conteúdo de $file é reduzido a $_ (consulte Implicações de segurança da execução de perl -ne '…' * , embora para considerações de segurança com essa construção. -pi fornece edição no local, $_ é gravado no arquivo depois que o código é executado. Em seguida, chamamos substr para substituir o caractere 1 no deslocamento fornecido por c .

    
por 11.08.2015 / 14:16
0

Tente isso se isso ajudar

sed 's/^\(.\{'"${rand1}"'\}\)./G/'  new_string.txt
    
por 11.08.2015 / 14:05
0

Com o novo GNU sed você pode fazer isso mesmo sem \n ewline remove

sed -z "s/./@/$(($RANDOM%$(wc -m < file.txt)))" file.txt
    
por 11.08.2015 / 15:08

Tags