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 .