Estoy intentando agregar texto al final de una línea las primeras x veces que ocurre. Sé cómo hacerlo globalmente y por si acaso. No puedo entender cómo hacerlo durante las primeras enésimas apariciones. Un ejemplo sería un archivo text.txt que contenga:
This is a test
junk
This is a test
More junk
This is a test
This is a test
This is a test
Y quiero agregar un '.' al final de las tres primeras veces que aparece "Esto es una prueba". El resultado que estoy tratando de obtener es:
This is a test.
junk
This is a test.
More junk
This is a test.
This is a test
This is a test
Respuesta1
This.*test
es la expresión regular correcta. El asterisco significa "0 o más veces el carácter anterior", por lo que This*test
no coincidiría con ninguna de sus líneas.
Ahora, Sed es malo en Aritmética. Para algo elegante sugiero Awk:
awk '/This.*test/{c++};{print $0 (c<4 ? "." : "")}' file
Creo que basta con decir que c
, como cualquier variable no configurada en Awk, se trata como cero, pero avíseme si necesita más aclaraciones.
Respuesta2
Otra variante que evita hacer la coincidencia de expresiones regulares después de que ya se hayan encontrado las 3 apariciones:
awk -v n=3 'n && /This is a test/ {n--; $0 = $0 "."}; {print}'
Específicamente sed
, podrías hacer algo como:
sed '
1 {
x
s/^/.../
x
}
/This is a test/ {
s/$/./
x
s/.//
/./ {
x
b
}
g
:1
$! {
n
b 1
}
}'
Donde realizamos un seguimiento del número de .
s para agregar como número correspondiente de .
s en el espacio de retención.
No hace falta decir que sed
es mucho menos apropiado para este tipo de tareas. Si el motivo del deseo sed
es la -i
extensión para la edición in situ que se encuentra en algunas implementaciones (tomada de perl
), tenga en cuenta que la implementación GNU de awk
también puede hacerlo con -i /usr/share/awk/inplace.awk
¹, o puede usar la versión real:
perl -lpi -e '
if ($n < 3 && /This is a test/) {
$n++;
$_ .= ".";
}' your-file
Si desea agregar un .
después de cada aparición de This is a test
en lugar de todas las líneas que contienen al menos una aparición de This is a test
, perl
también sería la mejor opción:
perl -pi -e 's{This is a test\K}{$n++ < 3 ? "." : ""}ge' your-file
¹no utilice-i inplace
as gawk
intenta cargar primero la inplace
extensión (como inplace
o inplace.awk
) desde el directorio de trabajo actual, donde alguien podría haber colocado malware. La ruta de la inplace
extensión suministrada gawk
puede variar según el sistema; consulte el resultado degawk 'BEGIN{print ENVIRON["AWKPATH"]}'
Respuesta3
Con perl
podríamos hacer lo que se muestra.
perl -lpe '
$_ = $k == 3 ? next : s/This is a test(?{$k++}).*\K/./r;
' file
Los elefantes también pueden bailar, aunque con pasos sencillos. Usando GNU sed
la escritura en su modo de expresión regular extendido, -E
podemos almacenar el recuento como número de nuevas líneas en la retención.
K=3
sed -Ee '
/This is a test/!b
G
/(.*\n){'"$K"'}.*\n/!{
s/\n+/./p;z;H;d
}
s/\n+//
:a;n;ba
' file