Bueno, no has puesto los requisitos ordenados, pero creo que se entiende:
"Si un registro del fichero1 termina con S, y existe una línea en fichero2 que comience con los caracteres (x, x+n) del registro, sustituir en él dichos caracteres por los caracteres (n, hasta fin de línea) de la línea del fichero2".
Sería bastante más fácil si los campos estuviesen delimitados por espacios, en vez de caracteres. Para separar campos por caracteres se usa 'cut'. Se me ocurre esta forma, que no está mal si el archivo no es gigante:
Código BASH:
Ver originalcp fichero1.dat fichero1.dat.original
while read linea; do
# obtenemos los pares (clave, valor) del fichero2
K=$(echo $linea | cut -c1-4)
V=$(echo $linea | cut -c5-)
sed -i 's/^\(.*\)'$K'\(.*\)S$/\1'$V'\2S/g' fichero1.dat # sustituimos todas las líneas de fichero1 que contengan la clave y terminen en S
done < fichero2.dat
El problema de esta solución es que lee y escribe fichero1 por cada línea de fichero2, con lo que si hablamos de decenas de miles de líneas, los tiempos de lectura+escritura del archivo pueden terminar siendo significativos.
Existe la posibilidad de leer todos los pares clave-valor de una vez, y luego hacer la sustitución línea por línea vía AWK, ya que awk soporta matrices asociativas. Otros lenguajes de programación, como Perl o Python, son una mejor opción si el programa tiene que hacer cosas más complejas.
Volviendo al tema de los campos delimitados por espacios, si tus archivos fuesen así:
Código BASH:
Ver original25742telefono1 mac1 577S
64523telefono2 mac2 655N
mac1 valor15
mac2 valor28
El comando join bastaría para resolver el problema (excepto, claro, por el asunto de que termine en S...):
# unir las líneas por el 2do campo del fichero1, y el 1er campo del fichero2, luego imprimir el primer campo del primer fichero, el segundo del segundo fichero, y el tercer campo del primer fichero.
Código BASH:
Ver original$ join -1 2 -2 1 -o 1.1 2.2 1.3 fichero1.dat fichero2.dat
25742telefono1 valor15 577S
64523telefono2 valor28 655N