Tengo un archivo con 50 caracteres en cada línea y 50 líneas. Cada línea del archivo contiene letras arbitrarias. Quiero especificar un número de secuencia de caracteres (por ejemplo, 52) e imprimir la línea de letras adecuada con un *
impreso delante del carácter dado.
Respuesta1
Codificando sus especificaciones, una forma sería calcular los números de línea y columna a partir del desplazamiento (ignorando las nuevas líneas) y usar esos valores para seleccionar la línea adecuada y resaltar la columna adecuada.
Con un archivo de entrada in
de 50 líneas como este:
00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
01ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
02ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
03ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
04ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
Entonces el siguiente script debería hacer aproximadamente lo que usted pidió:
while read -p '> ' n; do
n=$((n - 1))
line=$((n / 50 + 1))
col=$((n % 50))
<in sed -n -e "${line}p" | sed "s/^.\{${col}\}/&*/g"
done
Ejemplo de interacción:
> 1
*00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
> 2
0*0ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
> 49
00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst*uv
> 50
00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu*v
> 52
0*1ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
> 125
02ABCDEFGHIJKLMNOPQRSTUV*WXYZabcdefghijklmnopqrstuv
La primera llamada a sed selecciona la línea adecuada, la segunda inserta a *
en la columna adecuada.
Respuesta2
linemod50(){
dd bs=51 skip="$(($1/50))" count=1 | {
dd bs=1 count="$(($1%50-!!($1%50)))"
IFS= read -r rem
printf "*%s\n" "$rem"
} 2 >/dev/null
}
i= forty9=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW
while [ "$((i+=1))" -le 50 ]
do echo "$((i%10))$forty9"
done >file
linemod50 478 <file
1+0 records in
1+0 records out
51 bytes (51 B) copied, 9.5153e-05 s, 536 kB/s
0abcdefghijklmnopqrstuvwxyz*ABCDEFGHIJKLMNOPQRSTUVW
Probablemente sea la solución más eficiente porque dd
simplemente buscará directamente hasta su compensación. Sin embargo, no funciona con caracteres anchos y puede producir resultados inesperados con entradas canalizadas.
Es una excelente solución con entrada buscable en la configuración regional C.
Respuesta3
Usando GNU o FreeBSD sed
(para la -r
opción de expresión regular extendida):
Este script regresa al principio tanto para las líneas como para las posiciones de los caracteres. Si no desea que haga eso, comente o elimine la while
línea.
#! /bin/bash
for O in "$@" ; do
while [[ "$O" -gt 50 ]] ; do O=$(( $O -50 )) ; done
O1=$(( $O - 1 ))
sed -r -n "$O s/^(.{$O1})(.*)/\1\*\2/ p" input.txt
done
$ for i in {1..50} ; do printf "%02i%s\n" "$i" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv" ; done > input.txt
$ ./offset.sh 3 10 52 100
03*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
10ABCDEFG*HIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
0*2ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv
50ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu*v