¿Alguien puede sugerir una forma elegante de lograr esto?
Entrada:
test instant ()
test instant ()
...
test instant () //total 1000 lines
la salida debe ser:
test instant1 ()
test instant2 ()
test instant1000()
Las líneas vacías están en mis archivos de entrada y hay muchos archivos en el mismo directorio que necesito procesar a la vez.
Intenté esto para reemplazar muchos archivos en el mismo directorio y no funcionó.
for file in ./*; do perl -i -000pe 's/instance$& . ++$n/ge' "$file"; done
errores:
Substitution replacement not terminated at -e line 1.
Substitution replacement not terminated at -e line 1.
y también probé esto: perl -i -pe 's/instant/$& . ++$n/ge' *.vs
Funcionó, pero el índice siguió incrementándose de un archivo a otro. Me gustaría restablecer eso a 1 para el archivo diff. alguna buena sugerencia?
find . -type f -exec perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} +
funciona pero reemplazó todos los demás archivos no deben ser reemplazados. Prefiero reemplazar los archivos solo con "* .txt".
test instant ()
?Respuestas:
o con GNU
awk
:Para editar los archivos en el lugar, agregue la
-i
opción aperl
:O recursivamente:
Explicaciones
-p
es procesar la entrada línea por línea, evaluar la expresión pasada-e
para cada línea e imprimirla. Para cada línea, sustituimos (usando els/re/repl/flags
operador)instant
por sí mismo ($&
) y el valor incrementado de una variable++$n
. Lag
bandera es hacer la sustitución en todo el mundo (no sólo una vez), ye
por lo que la sustitución se interpreta como código de Perl para e valuar (no una cadena fija).Para la edición en el lugar donde una invocación perl procesa más de un archivo, queremos
$n
restablecer en cada archivo. En su lugar, usamos$n{$ARGV}
(donde$ARGV
está el archivo procesado actualmente).El
awk
que merece un poco de explicación.Estamos utilizando la capacidad de GNU
awk
para separar registros en cadenas arbitrarias (incluso expresiones regulares). Con-vRS=instant
, configuramos el separador de registro eninstant
.RT
es la variable que contiene lo que coincideRS
, por lo general,instant
excepto por el último registro donde será la cadena vacía. En la entrada anterior, los registros ($0
) y los terminadores de registro (RT
) son ([$0|RT]
):Entonces, todo lo que tenemos que hacer es insertar un número incremental al comienzo de cada registro, excepto el primero.
Que es lo que hacemos arriba. Para el primer registro,
n
estará vacío. Configuramos ORS (el separador de registro de salida ) a RT, para que seawk
impriman $0 RT
. Lo hace sobre la segunda expresión (++n
), que es una condición que siempre se evalúa como verdadera (un número distinto de cero) y, por lo tanto, la acción predeterminada (de impresión$0 ORS
) se realiza para cada registro.fuente
sed
Realmente no es la mejor herramienta para el trabajo, desea algo con mejores capacidades de secuencias de comandos. Aquí hay algunas opciones:perl
El
-p
medio "imprime cada línea" después de aplicar cualquier script que se le dé-e
. Las-000
vueltas en "modo de párrafo" lo que los registros (líneas) se definen por salto de línea consecutiva (\n
) caracteres, esto permite que se maneja correctamente las líneas a doble espacio.$&
es el último patrón coincidente y$.
es el número de línea actual del archivo de entrada. Ele
ens///e
me permite evaluar expresiones en el operador de sustitución.awk (esto supone que sus datos son exactamente como se muestran, con tres campos separados por espacios)
Aquí, incrementamos la
k
variablek
solo si la línea actual no está vacía,/./
en cuyo caso también imprimimos la información necesaria. Las líneas vacías se imprimen tal cual.varias conchas
Aquí, cada línea de entrada se divide automáticamente en espacios en blanco y los campos se guardan como
$a
,$b
y$c
. Luego, dentro del ciclo,$c
se aumenta en uno para cada línea para la que$a
no está vacía y su valor actual se imprime al lado del segundo campo$b
,.NOTA: todas las soluciones anteriores suponen que todas las líneas del archivo tienen el mismo formato. Si no, la respuesta de @ Stephane es el camino a seguir.
Para tratar con muchos archivos y suponer que desea hacer esto a todos los archivos en el directorio actual, puede usar esto:
CUIDADO: Esto supone nombres de archivos simples, sin espacios, si es necesario para hacer frente a algo más complejo, ir a (suponiendo
ksh93
,zsh
obash
):fuente