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
.