sed '/^.\{19\}RM99999/s/10/65/' <in >out
Substituirá a primeira ocorrência da string 10 pela string 65 em uma linha onde a string RM99999 começa no 20º caractere.
Acho que alguns acham que o 17º campo deve ser substituído. Eu realmente não entendo porque eu não posso ver isso na pergunta, mas se é o que você quer ...
sed '/^.\{19\}RM99999/s/[^|]*/65/17' <in >out
... que substituirá o campo 17th |
delimitado pela string 65 em uma linha onde a string RM99999 começa no 20º caractere.
Eu meio que estou apenas agarrando canudos, mas talvez eles signifiquem apenas 10 e apenas no 17º campo, e apenas em linhas onde RM99999 inicia 20 caracteres em? É um pouco mais difícil ...
sed -e'/^.\{19\}RM99999/s/|/|\n/16' \
-e's/\n\([^|]*\)10/5/;s/\n//' <in >out
... mas isso vai fazer isso. Venha para pensar sobre isso, parece um pouco mais parecido com o seu próprio código. Talvez seja o que é desejado depois de tudo.
Este é um pouco mais direto ...
sed -e'/^.\{19\}RM99999/!b' \
-e's/|\([^|]*10\)*/&\n/16' \
-e's/10\n/65/;s/\n//'
E isso acontece de uma só vez - se a contagem de campos for fixa, ou seja,
sed -e'/^.\{19\}RM99999/s/10\([^|]*\(|[^|]*\)\{7\}\)$/65/'
Você pode fazer a mesma coisa no front end, é claro ...
sed -e'/^.\{19\}RM99999/s/^\([^|]*\(|[^|]*\)\{16\}\)10/5/'
Mas como há mais da metade dos campos para a cauda, provavelmente é melhor não saber se ela pode ser ajudada.
E é um pouco mais fácil escrever com a sintaxe regexp estendida:
sed -Ee'/^.{19}RM99999/s/10([^|]*(\|[^|]*){7})$/65/'