Selección de la siguiente línea CSH foreach
Resuelto
visiteurr
-
visiteurr -
visiteurr -
Hola,
Trabajo bajo el Shell CSH, en un recorrido de archivo deseo comparar el elemento de la primera columna de la línea N con el elemento de la primera columna de la línea N+1. No puedo hacerlo... :/
¿Cómo puedo recuperar un elemento en N+1?
En Gro tengo un archivo del tipo
simon ok x
simon ok x
simon ok x
simon ok x
fabien ok x
fabien ok x
seb ok x
yoann ok x
yoann ok x
yoann ok x
yoann ok x
yoann ok x
yoann ok x
y quiero obtener esto:
simon ok 4
simon ok 4
simon ok 4
simon ok 4
fabien ok 2
fabien ok 2
seb ok 1
yoann ok 6
yoann ok 6
yoann ok 6
yoann ok 6
yoann ok 6
yoann ok 6
el archivo a tratar es muy grande, por lo tanto intento hacer algo ligero...
por ahora no estoy logrando nada, pruebo pero nada funciona
ej:
#! /bin/csh -f
foreach line ( "'cat tttt'" )
set argv = ( $line )
set name1 = $1
set name2 = $3
if ( $1 == $1 + 1) then
echo " $1 y '$1+1' prueba verdadera "
else
echo " $1 y 'expr $1 + 1' prueba falsa "
endif
end
así que, si alguien tiene una idea para realizar un script así en CSH... (no soy bueno en CSH, pero no elegí mi entorno de trabajo, lamentablemente :/ )
gracias de antemano
Trabajo bajo el Shell CSH, en un recorrido de archivo deseo comparar el elemento de la primera columna de la línea N con el elemento de la primera columna de la línea N+1. No puedo hacerlo... :/
¿Cómo puedo recuperar un elemento en N+1?
En Gro tengo un archivo del tipo
simon ok x
simon ok x
simon ok x
simon ok x
fabien ok x
fabien ok x
seb ok x
yoann ok x
yoann ok x
yoann ok x
yoann ok x
yoann ok x
yoann ok x
y quiero obtener esto:
simon ok 4
simon ok 4
simon ok 4
simon ok 4
fabien ok 2
fabien ok 2
seb ok 1
yoann ok 6
yoann ok 6
yoann ok 6
yoann ok 6
yoann ok 6
yoann ok 6
el archivo a tratar es muy grande, por lo tanto intento hacer algo ligero...
por ahora no estoy logrando nada, pruebo pero nada funciona
ej:
#! /bin/csh -f
foreach line ( "'cat tttt'" )
set argv = ( $line )
set name1 = $1
set name2 = $3
if ( $1 == $1 + 1) then
echo " $1 y '$1+1' prueba verdadera "
else
echo " $1 y 'expr $1 + 1' prueba falsa "
endif
end
así que, si alguien tiene una idea para realizar un script así en CSH... (no soy bueno en CSH, pero no elegí mi entorno de trabajo, lamentablemente :/ )
gracias de antemano
11 respuestas
Bon, es para un shell bash, necesitarás adaptar la sintaxis para el csh...
;-))
--
Zen mis nuggets ;-)
Haz un gesto por el medio ambiente, cierra tus ventanas y adopta un pingüino.
$ cat plop simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete $ cat foo.sh #! /bin/bash #set -xv while read line do sed -i "/${line% *}/{s/ok x/ok ${line#* }/}" plop done < <(awk '{ print $1 }' plop | uniq -c | awk '{ print $2,$1 }') $ ./foo.sh $ cat plop simon ok 4 febgeg simon ok 4 rhedg simon ok 4 erze simon ok 4 srg e fabien ok 2 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 6 eth yoann ok 6 et he yoann ok 6 ehe yoann ok 6 egr yoann ok 6 ereh yoann ok 6 ete $ ;-))
--
Zen mis nuggets ;-)
Haz un gesto por el medio ambiente, cierra tus ventanas y adopta un pingüino.
$ cat plop simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete $ cat csh_foo.csh #! /bin/csh foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' ) set line = "$line:gas/|/ /" set argv = ( $line ) sed "/$1/{s/ok x/ok $2/}" plop > blop mv blop plop end $ ./csh_foo.csh $ cat plop simon ok 4 febgeg simon ok 4 rhedg simon ok 4 erze simon ok 4 srg e fabien ok 2 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 6 eth yoann ok 6 et he yoann ok 6 ehe yoann ok 6 egr yoann ok 6 ereh yoann ok 6 ete $ ;-))
--
Zen mis nuggets ;-)
Haced un gesto por el medio ambiente, cerrad vuestras ventanas y adoptad un pingüino.
RE Gracias ^^
Él me devuelve eso: "Falta }"
nada más, es raro... intenté modificar (reemplazar las llaves, etc... pero nada funciona, siempre da errores.
Pero no entiendo, ¿tú hiciste eso en una consola en CSH entonces por qué no funciona en mi caso? rrrr ¿por qué nunca tengo suerte con la informática? :/
Él me devuelve eso: "Falta }"
nada más, es raro... intenté modificar (reemplazar las llaves, etc... pero nada funciona, siempre da errores.
Pero no entiendo, ¿tú hiciste eso en una consola en CSH entonces por qué no funciona en mi caso? rrrr ¿por qué nunca tengo suerte con la informática? :/
Re-
Me responde esto: "Falta }"
nada más, es raro... he intentado modificar (reemplazar las llaves, etc... pero nada funciona, siempre da errores.
Intenta proceder poco a poco (es lo que hice ayer, ya que el csh no es mi fuerte y tenía errores como tú, especialmente el famoso "Falta }" ;-((
Así que para empezar:
Y ve si sigues teniendo errores.
Sin embargo, ten cuidado, el código del foro interpreta muy mal las comillas inversas " ' " (Alt Gr + 7 el 7 del teclado alfanumérico, el que está encima de las teclas Y y U), así que en la expresión:
foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' )
es realmente una comilla inversa antes del primer awk y antes del último paréntesis de cierre, ¿verdad?
Pero no entiendo, hiciste esto en una consola en CSH, así que ¿por qué no funciona en mi caso? rrrr ¿por qué nunca tengo suerte con la informática? :/
Tuve que instalarlo ayer en una Mandriva 2010, ya no se proporciona por defecto, y a este respecto se instaló tcsh, quizás eso tenga que ver; -\
Me responde esto: "Falta }"
nada más, es raro... he intentado modificar (reemplazar las llaves, etc... pero nada funciona, siempre da errores.
Intenta proceder poco a poco (es lo que hice ayer, ya que el csh no es mi fuerte y tenía errores como tú, especialmente el famoso "Falta }" ;-((
Así que para empezar:
#! /bin/csh foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' ) echo $line end Y ve si sigues teniendo errores.
Sin embargo, ten cuidado, el código del foro interpreta muy mal las comillas inversas " ' " (Alt Gr + 7 el 7 del teclado alfanumérico, el que está encima de las teclas Y y U), así que en la expresión:
foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' )
es realmente una comilla inversa antes del primer awk y antes del último paréntesis de cierre, ¿verdad?
Pero no entiendo, hiciste esto en una consola en CSH, así que ¿por qué no funciona en mi caso? rrrr ¿por qué nunca tengo suerte con la informática? :/
Tuve que instalarlo ayer en una Mandriva 2010, ya no se proporciona por defecto, y a este respecto se instaló tcsh, quizás eso tenga que ver; -\
$ ls -l /bin/csh lrwxrwxrwx 1 root root 4 2011-02-02 15:19 /bin/csh -> tcsh* $ urpmq -fi tcsh Nombre : tcsh Versión : 6.15 Lanzamiento : 6.4mdv2010.0 Grupo : Shells Tamaño : 616513 Arquitectura: i586 Fuente RPM : tcsh-6.15-6.4mdv2010.0.src.rpm URL : http://www.tcsh.org/ Resumen : Una versión mejorada de csh, el C shell Descripción : Tcsh es una versión mejorada pero completamente compatible de csh, el C shell. Tcsh es un intérprete de lenguaje de comandos que se puede usar tanto como un shell de inicio interactivo como un procesador de comandos de script de shell. Tcsh incluye un editor de línea de comandos, finalización de palabras programable, corrección ortográfica, un mecanismo de historial, control de trabajos y una sintaxis similar al lenguaje C.
foreach line ( 'awk '{ print $1 }' plop | uniq -c | awk '{ printf "%s|%s\n",$2,$1 }'' )
echo $line
end
¡funciona muy bien!
sin embargo, cuando lo pongo todo (con las comillas correctas ^^) da: Variable syntax
solo hay una variable creo: $line y no veo por qué !
Como habrás notado, soy muy malo en CSH :/ lo siento>
Hola,
En caso de que... existen herramientas listas bajo GNU/Linux...
;-))
--
Zen mis nuggets ;-)
Haz un gesto por el medio ambiente, cierra tus ventanas y adopta un pingüino.
En caso de que... existen herramientas listas bajo GNU/Linux...
$ cat plop simon ok x simon ok x simon ok x simon ok x fabien ok x fabien ok x seb ok x yoann ok x yoann ok x yoann ok x yoann ok x yoann ok x yoann ok x $ uniq -c plop 4 simon ok x 2 fabien ok x 1 seb ok x 6 yoann ok x $
;-))
--
Zen mis nuggets ;-)
Haz un gesto por el medio ambiente, cierra tus ventanas y adopta un pingüino.
gracias por tu respuesta. Sin embargo, eso compara las líneas y yo solo quiero comparar la primera columna.
Porque, por ejemplo, con
simon ok x febgeg
simon ok x rhedg
simon ok x erze
simon ok x srg e
fabien ok x nrteth
fabien ok x tehhet
seb ok x et ee
yoann ok x eth
yoann ok x et he
yoann ok x ehe
yoann ok x egr
yoann ok x ereh
yoann ok x ete
no funciona :/
y es un archivo enorme, así que lo mejor sería modificarlo directamente:
Sabiendo que las líneas con la primera columna igual se siguen necesariamente (uf)
Contar el número de ocurrencias del primer término (ej: simon) y luego poner en la tercera columna este número.
en resumen:
L1 simon -> count = 1
L2 simon -> count = 2
L3 simon -> count = 3
L4 simon -> count = 4
L5 fabien -> count = 4 y ponemos 4 en la tercera columna de simon y luego reiniciamos count a 0
eso es en resumen lo que quiero hacer...
pero, de todos modos, ya me gustaría saber: ¿Cómo recuperar un elemento en N+1? (cf primera pregunta)
Muchas gracias.
Porque, por ejemplo, con
simon ok x febgeg
simon ok x rhedg
simon ok x erze
simon ok x srg e
fabien ok x nrteth
fabien ok x tehhet
seb ok x et ee
yoann ok x eth
yoann ok x et he
yoann ok x ehe
yoann ok x egr
yoann ok x ereh
yoann ok x ete
no funciona :/
y es un archivo enorme, así que lo mejor sería modificarlo directamente:
Sabiendo que las líneas con la primera columna igual se siguen necesariamente (uf)
Contar el número de ocurrencias del primer término (ej: simon) y luego poner en la tercera columna este número.
en resumen:
L1 simon -> count = 1
L2 simon -> count = 2
L3 simon -> count = 3
L4 simon -> count = 4
L5 fabien -> count = 4 y ponemos 4 en la tercera columna de simon y luego reiniciamos count a 0
eso es en resumen lo que quiero hacer...
pero, de todos modos, ya me gustaría saber: ¿Cómo recuperar un elemento en N+1? (cf primera pregunta)
Muchas gracias.
Por ejemplo, esto es lo que veo
:~$ cat visiteurr simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete :~$ perl -ne 's/^(.*?)\s.*/$1. "-> count " . ($h{$1}++ + 1)/e;print' visiteurr simon-> count 1 simon-> count 2 simon-> count 3 simon-> count 4 fabien-> count 1 fabien-> count 2 seb-> count 1 yoann-> count 1 yoann-> count 2 yoann-> count 3 yoann-> count 4 yoann-> count 5 yoann-> count 6
:~$ cat visiteurr simon ok 1 febgeg simon ok 2 rhedg simon ok 3 erze simon ok 4 srg e fabien ok 1 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 1 eth yoann ok 2 et he yoann ok 3 ehe yoann ok 4 egr yoann ok 5 ereh yoann ok 6 ete :~$ perl -ne 's/^(.*?)\s(.*?)\sx(.*)/"$1 $2 " .($h{$1}++ + 1) . "$3"/e;print' visiteurr simon ok 1 febgeg simon ok 2 rhedg simon ok 3 erze simon ok 4 srg e fabien ok 1 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 1 eth yoann ok 2 et he yoann ok 3 ehe yoann ok 4 egr yoann ok 5 ereh yoann ok 6 ete
Re,
Bueno, debe haber algo más simple, pero estoy pensando en algo como:
- obtenemos el número de ocurrencias y las guardamos en un archivo temporal
- utilizamos el archivo temporal e insertamos el número de ocurrencias en el archivo
--
GNU/Linux: ¡Linux no es Ubuntu! Elegir qué Linux utilizar no significa tu distribución favorita,
106485010510997108
Bueno, debe haber algo más simple, pero estoy pensando en algo como:
- obtenemos el número de ocurrencias y las guardamos en un archivo temporal
:~$ perl -ane '$h{$F[0]}++;END{print "$_:$h{$_}\n" for keys %h}' visiteurr > visiteurr.occ lami20j@debian-acer:~$ cat visiteurr.occ seb:1 yoann:6 simon:4 fabien:2 - utilizamos el archivo temporal e insertamos el número de ocurrencias en el archivo
:~$ cat visiteurr simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete :~$ perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr simon ok 4 febgeg simon ok 4 rhedg simon ok 4 erze simon ok 4 srg e fabien ok 2 nrteth fabien ok 2 tehhet seb ok 1 et ee yoann ok 6 eth yoann ok 6 et he yoann ok 6 ehe yoann ok 6 egr yoann ok 6 ereh yoann ok 6 ete --
GNU/Linux: ¡Linux no es Ubuntu! Elegir qué Linux utilizar no significa tu distribución favorita,
106485010510997108
Re-
Normalmente Perl está instalado en todos los sistemas GNU/Linux por defecto y no depende en nada del shell de conexión.
También se supone que es más adecuado para este tipo de procesamiento ;-))
PD. Estoy respondiendo en su lugar sabiendo que no se conectará hasta esta noche, a menos que quiera hacerme mentir ;-))
Normalmente Perl está instalado en todos los sistemas GNU/Linux por defecto y no depende en nada del shell de conexión.
También se supone que es más adecuado para este tipo de procesamiento ;-))
PD. Estoy respondiendo en su lugar sabiendo que no se conectará hasta esta noche, a menos que quiera hacerme mentir ;-))
¡Vaya! J'ai rien modifié à part les noms de fichier et j'ai l'impression que ça marche... Je comprends pas, lol.
¿Dónde seleccionamos la columna a modificar? ¿Podrías explicarme este comando?
:~$ perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
¿Dónde seleccionamos la columna a modificar? ¿Podrías explicarme este comando?
:~$ perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
Hola,
1er pedido
perl -ane '$h{$F[0]}++;END{print "$_:$h{$_}\n" for keys %h}' visiteurr > visiteurr.occ
El papel de este comando es contar el número de ocurrencias de la palabra que se encuentra al principio de las líneas del archivo.
Para ello, utilizo la estructura de datos llamada hash o tabla asociativa.
Esta estructura de datos permite acceder a los elementos de la tabla mediante una clave (que es una cadena de caracteres).
A cada clave le corresponde un valor (que puede ser una cadena, un número, un array, un hash, una referencia, en fin, un poco de todo ;-)
Lo que da la presentación siguiente
A saber que la clave es única.
En tu ejemplo, el comando va a recorrer cada línea del archivo.
Dado que buscamos el número de ocurrencias de la 1ª palabra de cada línea, solo es necesario considerar la 1ª palabra como clave y dado que debería ser única, pronto solo tendré que contar el valor.
Esto es lo que sucede en el fondo.
Tratamiento de la 1ª línea
la clave es simon y el valor será 1
Tratamiento de la 2ª línea
la clave es simon y el valor será 2 (el valor se incrementa en cada paso)
Todo esto para todos los simon, cualquiera que sea el número de la línea en el archivo (así que las líneas que tienen simon al principio no necesitan ser agrupadas)
Cuando llegamos a fabien, es una nueva clave y al igual que la clave simon, el valor se incrementará y así sucesivamente hasta la última línea del archivo.
Al final, el hash tiene un poco esta forma (a saber que se puede ordenar el hash, pero no es necesario en este caso) que es interna, por lo tanto aleatoria y no en el orden de creación del hash
En ese momento, el hash está en la memoria RAM y habría que guardarlo en alguna parte, yo elegí un archivo.
El bloque END{} permite, una vez llegado al final del archivo, mostrar el hash.
Para guardar en el archivo, utilicé una simple redirección de STDOUT (salida estándar, la pantalla) hacia un archivo.
Así funciona el 1er comando.
Las opciones utilizadas permiten dividir las palabras de cada línea en un array @F y luego utilizo $F[0] - el 1er elemento (simon, seb, fabien, yoann)
El 2º pedido
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
Este comando lee los dos archivos:
- el creado por el 1er comando que contiene el número de ocurrencias
- el archivo original.
El comando contiene dos líneas de código separadas por punto y coma
$h{$1}=$2 if /(.*):(.*)/
y
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
El comando $h{$1}=$2 if /(.*):(.*)/ en el momento de leer el 1er archivo va a recrear el hash.
Esta vez, el separador ya no es el espacio, sino los dos puntos
(.*):(.*), es una expresión regular que podríamos traducir así
. significa cualquier carácter
* es un cuantificador que permite encontrar 0, 1 o cualquier cantidad de caracteres
() los paréntesis son para capturar el patrón encontrado
: es el carácter literal
Las capturas están numeradas del 1 al .... y las variables correspondientes son $1, $2 .....
Lo que es interesante es que el hash se llenará si y solo si la línea contiene un : (esto podría plantear problemas de memoria, no habrá resultado si el archivo original contiene :)
Podríamos mejorar utilizando anclajes de inicio y fin de cadena. (^ - inicio; $ - fin)
Podrías preguntarte por qué no lo hicimos de una vez en lugar de crear un archivo temporal.
Si el archivo es de gran tamaño (digamos millones de líneas), entonces te dejo imaginar cuánta memoria RAM + swap deberíamos tener para almacenar todo esto.
Bueno, el caso más desfavorable será si el archivo original contiene una clave por línea, pero en ese caso ya no habrá necesidad de contar el número de ocurrencias y en ese caso, la adición del 1 en la columna sería suficiente
Por lo tanto, $h{$1}=$2 if /(.*):(.*)/ dice en resumen: llena el hash con clave => valor si y solo si la línea leída en el archivo contiene :
Al final de la lectura del 1er archivo, el hash está lleno y comienza la lectura del archivo original.
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
Sabiendo que el separador es el espacio, solo hay que separar las palabras y luego reemplazar la x con el valor correspondiente que se encuentra en el hash
s/MOTIVO/REEMPLAZO/ es la función de sustitución que permite reemplazar la parte izquierda con lo que se encuentra a la derecha
La parte MOTIVO
s/^(.*?)\s(.*?)\sx(.*)/
s/
^ -anclaje inicio cadena
( - inicio 1ª captura - $1
.*? - cualquier carácter 0, 1 o cualquier cantidad de veces pero evitando la codicia
) - fin 1ª captura
\s - busca un espacio
( - inicio 2ª captura - $2
.*? - cualquier carácter 0, 1 o cualquier cantidad de veces pero evitando la codicia
) - fin 2ª captura
\sx - aquí está el campo concerniente para el cambio
( - la 3ª captura - $3
.* - cualquier carácter 0, 1 o cualquier cantidad de veces, codicioso esta vez
) - fin de la 3ª captura
Atención, si la columna que tiene que ser modificada no contiene x, entonces habría que cambiar la regex
La parte REEMPLAZO
/$1 $2 $h{$1} $3/ and print
/
$1 - la 1ª captura
$2 - espacio la 2ª captura
$h{$1} - espacio y ver (número de ocurrencias)
$3 - espacio y la 3ª captura
/ and print - fin de reemplazo y muestra
número de ocurrencia $h{$1}
La 1ª captura es la 1ª palabra de la línea.
$h{$1} por ejemplo, cuando la palabra es simon tenemos:
$h{"simon"} y en el hash vimos que el valor de simon es el número de ocurrencias encontradas por el 1er comando, así que 4
Esta sustitución se aplica para cada línea.
Así que, espero que sea un poco más claro.
es él el especialista en Perl ;-))
No es mentiroso en lo que respecta a la conexión, pero en lo demás sí ;-))
1er pedido
perl -ane '$h{$F[0]}++;END{print "$_:$h{$_}\n" for keys %h}' visiteurr > visiteurr.occ
El papel de este comando es contar el número de ocurrencias de la palabra que se encuentra al principio de las líneas del archivo.
Para ello, utilizo la estructura de datos llamada hash o tabla asociativa.
Esta estructura de datos permite acceder a los elementos de la tabla mediante una clave (que es una cadena de caracteres).
A cada clave le corresponde un valor (que puede ser una cadena, un número, un array, un hash, una referencia, en fin, un poco de todo ;-)
Lo que da la presentación siguiente
%hash = ( "clave1" => "valor", "clave2" => "otro valor", .... "claveN" => "y aún otro valor", );
A saber que la clave es única.
En tu ejemplo, el comando va a recorrer cada línea del archivo.
Dado que buscamos el número de ocurrencias de la 1ª palabra de cada línea, solo es necesario considerar la 1ª palabra como clave y dado que debería ser única, pronto solo tendré que contar el valor.
Esto es lo que sucede en el fondo.
Tratamiento de la 1ª línea
la clave es simon y el valor será 1
Tratamiento de la 2ª línea
la clave es simon y el valor será 2 (el valor se incrementa en cada paso)
Todo esto para todos los simon, cualquiera que sea el número de la línea en el archivo (así que las líneas que tienen simon al principio no necesitan ser agrupadas)
Cuando llegamos a fabien, es una nueva clave y al igual que la clave simon, el valor se incrementará y así sucesivamente hasta la última línea del archivo.
Al final, el hash tiene un poco esta forma (a saber que se puede ordenar el hash, pero no es necesario en este caso) que es interna, por lo tanto aleatoria y no en el orden de creación del hash
%h = ( "seb" => 1, "yoann" => 6, "simon" => 4, "fabien" => 2, );
En ese momento, el hash está en la memoria RAM y habría que guardarlo en alguna parte, yo elegí un archivo.
El bloque END{} permite, una vez llegado al final del archivo, mostrar el hash.
Para guardar en el archivo, utilicé una simple redirección de STDOUT (salida estándar, la pantalla) hacia un archivo.
Así funciona el 1er comando.
Las opciones utilizadas permiten dividir las palabras de cada línea en un array @F y luego utilizo $F[0] - el 1er elemento (simon, seb, fabien, yoann)
El 2º pedido
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print' visiteurr.occ visiteurr
Este comando lee los dos archivos:
- el creado por el 1er comando que contiene el número de ocurrencias
- el archivo original.
El comando contiene dos líneas de código separadas por punto y coma
$h{$1}=$2 if /(.*):(.*)/
y
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
El comando $h{$1}=$2 if /(.*):(.*)/ en el momento de leer el 1er archivo va a recrear el hash.
Esta vez, el separador ya no es el espacio, sino los dos puntos
(.*):(.*), es una expresión regular que podríamos traducir así
. significa cualquier carácter
* es un cuantificador que permite encontrar 0, 1 o cualquier cantidad de caracteres
() los paréntesis son para capturar el patrón encontrado
: es el carácter literal
Las capturas están numeradas del 1 al .... y las variables correspondientes son $1, $2 .....
Lo que es interesante es que el hash se llenará si y solo si la línea contiene un : (esto podría plantear problemas de memoria, no habrá resultado si el archivo original contiene :)
Podríamos mejorar utilizando anclajes de inicio y fin de cadena. (^ - inicio; $ - fin)
Podrías preguntarte por qué no lo hicimos de una vez en lugar de crear un archivo temporal.
Si el archivo es de gran tamaño (digamos millones de líneas), entonces te dejo imaginar cuánta memoria RAM + swap deberíamos tener para almacenar todo esto.
Bueno, el caso más desfavorable será si el archivo original contiene una clave por línea, pero en ese caso ya no habrá necesidad de contar el número de ocurrencias y en ese caso, la adición del 1 en la columna sería suficiente
Por lo tanto, $h{$1}=$2 if /(.*):(.*)/ dice en resumen: llena el hash con clave => valor si y solo si la línea leída en el archivo contiene :
Al final de la lectura del 1er archivo, el hash está lleno y comienza la lectura del archivo original.
s/^(.*?)\s(.*?)\sx(.*)/$1 $2 $h{$1} $3/ and print
Sabiendo que el separador es el espacio, solo hay que separar las palabras y luego reemplazar la x con el valor correspondiente que se encuentra en el hash
s/MOTIVO/REEMPLAZO/ es la función de sustitución que permite reemplazar la parte izquierda con lo que se encuentra a la derecha
La parte MOTIVO
s/^(.*?)\s(.*?)\sx(.*)/
s/
^ -anclaje inicio cadena
( - inicio 1ª captura - $1
.*? - cualquier carácter 0, 1 o cualquier cantidad de veces pero evitando la codicia
) - fin 1ª captura
\s - busca un espacio
( - inicio 2ª captura - $2
.*? - cualquier carácter 0, 1 o cualquier cantidad de veces pero evitando la codicia
) - fin 2ª captura
\sx - aquí está el campo concerniente para el cambio
( - la 3ª captura - $3
.* - cualquier carácter 0, 1 o cualquier cantidad de veces, codicioso esta vez
) - fin de la 3ª captura
Atención, si la columna que tiene que ser modificada no contiene x, entonces habría que cambiar la regex
La parte REEMPLAZO
/$1 $2 $h{$1} $3/ and print
/
$1 - la 1ª captura
$2 - espacio la 2ª captura
$h{$1} - espacio y ver (número de ocurrencias)
$3 - espacio y la 3ª captura
/ and print - fin de reemplazo y muestra
número de ocurrencia $h{$1}
La 1ª captura es la 1ª palabra de la línea.
$h{$1} por ejemplo, cuando la palabra es simon tenemos:
$h{"simon"} y en el hash vimos que el valor de simon es el número de ocurrencias encontradas por el 1er comando, así que 4
Esta sustitución se aplica para cada línea.
Así que, espero que sea un poco más claro.
es él el especialista en Perl ;-))
No es mentiroso en lo que respecta a la conexión, pero en lo demás sí ;-))
Hola,
La verdad es que mi prueba se basa en un ejemplo que parece no estar conforme a tu archivo.
Por eso quizás necesite tu archivo.
¿Puedes enviármelo por email?
Pequeña precisión también... ¿cuál es la diferencia entre ".*?" y solo ".*"?
Aquí hay un ejemplo para ver la diferencia.
Te das cuenta de que cuando uso .* a entonces $1 vale xigenc - .* ha consumido todo hasta la última e, por lo tanto la cadena más larga.
Sin embargo, cuando uso .*? entonces $1 vale xig - .*? ha consumido hasta la 1ª e, por lo tanto la cadena mínima.
La verdad es que mi prueba se basa en un ejemplo que parece no estar conforme a tu archivo.
Por eso quizás necesite tu archivo.
¿Puedes enviármelo por email?
Pequeña precisión también... ¿cuál es la diferencia entre ".*?" y solo ".*"?
Aquí hay un ejemplo para ver la diferencia.
Te das cuenta de que cuando uso .* a entonces $1 vale xigenc - .* ha consumido todo hasta la última e, por lo tanto la cadena más larga.
Sin embargo, cuando uso .*? entonces $1 vale xig - .*? ha consumido hasta la 1ª e, por lo tanto la cadena mínima.
:~$ echo exigence exigence :~$ echo exigence | perl -ne '/e(.*)e/ ; print "$1\n"' xigenc r:~$ echo exigence | perl -ne '/e(.*?)e/ ; print "$1\n"' xig
Hola,
Para eso tal vez necesitaría tu archivo.
¿Puedes enviármelo por correo?
Ya lo he solicitado, pero no es posible, sin embargo las líneas originales se parecen a esto ;-\
Para eso tal vez necesitaría tu archivo.
¿Puedes enviármelo por correo?
Ya lo he solicitado, pero no es posible, sin embargo las líneas originales se parecen a esto ;-\
Hola,
Ya se ha preguntado, pero no es posible, sin embargo las líneas originales se parecen
Bueno, es precisamente eso lo que me molesta que se parezca, pero nadie dice lo que hay detrás de los caracteres no imprimibles (espacio, tabulación, o no sé qué más ;-)
Voy a intentar generalizar.
Ya se ha preguntado, pero no es posible, sin embargo las líneas originales se parecen
Bueno, es precisamente eso lo que me molesta que se parezca, pero nadie dice lo que hay detrás de los caracteres no imprimibles (espacio, tabulación, o no sé qué más ;-)
Voy a intentar generalizar.
Re,
no entiendo cómo "simular" columnas ...
¿Sabes?
Entonces vamos a intentar averiguar la estructura de tu archivo.
Con este comando, todos los caracteres diferentes de los espacios y tabulaciones son reemplazados por A y los otros por su código ascii.
perl -ne 'while(/(.)/g){my $x=$1;($x=~/\s/)?(print " ", ord($x), " "):print "A"};print "\n"' visiteurr > visit.struct
Después pones el archivo visit.struct en cjoint.com
Como prueba, aquí está lo que se muestra en mi caso
--
GNU/Linux: ¡Linux no es Ubuntu! Elegir qué linux usar no significa tu distribución favorita,
106485010510997108
no entiendo cómo "simular" columnas ...
¿Sabes?
Entonces vamos a intentar averiguar la estructura de tu archivo.
Con este comando, todos los caracteres diferentes de los espacios y tabulaciones son reemplazados por A y los otros por su código ascii.
perl -ne 'while(/(.)/g){my $x=$1;($x=~/\s/)?(print " ", ord($x), " "):print "A"};print "\n"' visiteurr > visit.struct
Después pones el archivo visit.struct en cjoint.com
Como prueba, aquí está lo que se muestra en mi caso
~$ cat visiteurr simon ok x febgeg simon ok x rhedg simon ok x erze simon ok x srg e fabien ok x nrteth fabien ok x tehhet seb ok x et ee yoann ok x eth yoann ok x et he yoann ok x ehe yoann ok x egr yoann ok x ereh yoann ok x ete ~$ perl -ne 'while(/(.)/g){my $x=$1;($x=~/\s/)?(print " ", ord($x), " "):print "A"};print "\n"' visiteurr > visit.struct lami20j@debian-acer:~$ cat visit.struct AAAAA 32 AA 32 A 32 AAAAAA AAAAA 32 AA 32 A 32 AAAAA AAAAA 32 AA 32 A 32 AAAA AAAAA 32 AA 32 A 32 AAA 32 A AAAAAA 32 AA 32 A 32 AAAAAA AAAAAA 32 AA 32 A 32 AAAAAA AAA 32 AA 32 A 32 AA 32 AA AAAAA 32 AA 32 A 32 AAA AAAAA 32 AA 32 A 32 AA 32 AA AAAAA 32 AA 32 A 32 AAA AAAAA 32 AA 32 A 32 AAA AAAAA 32 AA 32 A 32 AAAA AAAAA 32 AA 32 A 32 AAA 32 --
GNU/Linux: ¡Linux no es Ubuntu! Elegir qué linux usar no significa tu distribución favorita,
106485010510997108
Hola,
¿es normal que funcione o es cuestión de suerte y no va a funcionar todo el tiempo?
Lo que necesito no es el contenido sino la estructura de tu archivo.
Bueno, si el decir que hay una palabra separada por un espacio o tabulación es una amenaza a la seguridad, entonces están paranoicos ;-)
Lo que me interesa es el separador de campo y qué columna quieres reemplazar.
y funciona muy bien
No estoy convencido.
Tu comando y tu línea de archivo son dos cosas diferentes.
Veo en tu regex entre la 1ª y la 2ª captura un dos puntos, pero no en la línea de tu archivo.
¿es normal que funcione o es cuestión de suerte y no va a funcionar todo el tiempo?
Lo que necesito no es el contenido sino la estructura de tu archivo.
Bueno, si el decir que hay una palabra separada por un espacio o tabulación es una amenaza a la seguridad, entonces están paranoicos ;-)
Lo que me interesa es el separador de campo y qué columna quieres reemplazar.
y funciona muy bien
No estoy convencido.
Tu comando y tu línea de archivo son dos cosas diferentes.
Veo en tu regex entre la 1ª y la 2ª captura un dos puntos, pero no en la línea de tu archivo.
re,
Veo en tu regex entre la 1ª y la 2ª captura un dos puntos, pero no en la línea de tu archivo.
pienso que el if /(.*):(.*)/ se refiere al archivo .occ, ¿no?
efectivamente son paranoicos ^^ es el problema de las grandes multinacionales :/
Lo que necesito no es el contenido, sino la estructura de tu archivo.
el archivo está constituido por líneas de la misma estructura ... 20 columnas que contienen cada una una palabra (ej: test_53_du_01012011 <- eso es UNA palabra),
la columna a modificar es la 2ª
cuando lo abro con un "more" tengo la impresión de que el separador de columnas es una tabulación.
espero haber respondido a tu pregunta ... si necesitas más información no dudes en preguntar, intentaré responder de la mejor manera...
por cierto, para los ":" nunca he tenido un ":" en mi archivo a tratar.
thx ;)
Veo en tu regex entre la 1ª y la 2ª captura un dos puntos, pero no en la línea de tu archivo.
pienso que el if /(.*):(.*)/ se refiere al archivo .occ, ¿no?
efectivamente son paranoicos ^^ es el problema de las grandes multinacionales :/
Lo que necesito no es el contenido, sino la estructura de tu archivo.
el archivo está constituido por líneas de la misma estructura ... 20 columnas que contienen cada una una palabra (ej: test_53_du_01012011 <- eso es UNA palabra),
la columna a modificar es la 2ª
cuando lo abro con un "more" tengo la impresión de que el separador de columnas es una tabulación.
espero haber respondido a tu pregunta ... si necesitas más información no dudes en preguntar, intentaré responder de la mejor manera...
por cierto, para los ":" nunca he tenido un ":" en mi archivo a tratar.
thx ;)
Hola,
La línea que modificaste es correcta y en las líneas de tipo que mostraste funciona.
De hecho, en mi ejemplo, estaba haciendo el reemplazo en la tercera columna y tú lo quieres en la segunda.
Normalmente \s es una clase de caracteres que incluye la tabulación, por lo tanto, el \t
También querías una explicación para el .*?
Te he dado un ejemplo aquí https://forums.commentcamarche.net/forum/affich-20734055-selection-ligne-suivante-csh-foreach#50
Sin embargo, ten cuidado con lo que vayas a utilizar como regex en lugar de modificación.
Prueba esto
Para ver lo que hace .* en lugar de .*?
Puedes probar con
La línea que modificaste es correcta y en las líneas de tipo que mostraste funciona.
De hecho, en mi ejemplo, estaba haciendo el reemplazo en la tercera columna y tú lo quieres en la segunda.
Normalmente \s es una clase de caracteres que incluye la tabulación, por lo tanto, el \t
También querías una explicación para el .*?
Te he dado un ejemplo aquí https://forums.commentcamarche.net/forum/affich-20734055-selection-ligne-suivante-csh-foreach#50
Sin embargo, ten cuidado con lo que vayas a utilizar como regex en lugar de modificación.
Prueba esto
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s.*?\s(.*)/$1\t$h{$1}\t$2/ and print' texto.txt.occ texto.tmp.3_2 > resultado Para ver lo que hace .* en lugar de .*?
Puedes probar con
perl -ne '$h{$1}=$2 if /(.*):(.*)/;s/^(.*?)\s.*\s(.*)/$1\t$h{$1}\t$2/ and print;print "\n"' texto.txt.occ texto.tmp.3_2 > resultado2
Sin embargo, no puedo hacerlo en CSH :/ dado que la opción -i de sed no funciona en CSH :/
¿Alguien que conozca CSH podría ayudarme? (una vez más, gracias zipe31)