Ver la Versión Completa : Ayuda con comparación de cadenas en script en Bash
rrb32
30-10-2008, 22:46:06
Buenas.
Pues tengo que hacer unos scripts para la asignatura de Sistemas Operativos y tengo un problemilla en ellos.
Resulta que, utilizando AWK (o GAWK), leo el primer campo del fichero, que es un identificador numérico, y lo comparo con el dato de entrada por la consola, para saber sin son iguales. El problema es que, mira si la cadena de entrada coincide con la que hay en el fichero, de modo que si en el fichero hay 3100 y yo introduzco 100, me detecta como si estuviese ya, aunque esto no es cierto. ¿Hay alguna manera para comparar las cadenas exactamente? ¿O tendré que pasar los datos a número? Se puede hacer también con grep, pero considero más elegante con gawk.
Os pongo el código, por si puede ayudar. Quizás hay algún error, pero es que he retocado el archivo muchas veces, pero bueno, me interesa la comparación:
#!/bin/bash
if [ $# != 3 ]
then echo "No se han introducido todos los argumentos"
exit
fi
gawk -F: ' BEGIN {existe = false} \
{if ('$1'==$1) existe = true; exit} \
END {if (!existe) print("'$1':'$2':'$3'") >> "PASAJEROS"; else print "Error"} ' PASAJEROS
Muchas gracias.
Un saludo.
P.D.: no sé si me he explicado correctamente. Si es necesario, copio el enunciado de la práctica.
x7iBiT
31-10-2008, 04:37:07
Creo que el problema está en la forma que le pasas la variable al awk, que si no recuerdo mal era con un parámetro. Tengo que buscar las prácticas a ver exactamente como era (para ir a tiro hecho). En cuanto lo encuentre te digo (mañana ya, que me ahora me estoy cayendo).
Otra cosa que veo es que la estructura de ifs y elses que hay dentro del awk la veo un poquito liosa. Si es = a la columna 1 entonces imprime las 3 columnas, y si no "Error" (y ya está). Date cuenta que la variable existe en realidad no hace nada, sólo liarla más (tengo que verlo bien de todas formas, que ahora estoy un poco empanado).
De todas formas si la tuviera que hacer yo, no me complicaría: usaría el awk sólo para imprimir la primera columna (entera), y luego la filtraría con grep (cosa que se puede hacer en una sóla línea).
x7iBiT
31-10-2008, 14:29:49
Ya lo encontré. El parámetro es -v
Así por ejemplo, dentro de awk vamos a llamar i1 a $1 (por aquello input):
awk -v i1=$1 '{if (i1 == $1) print $1}'
Como te dije arriba otra forma más fácil sería:
awk '{print $1}' | grep $1
rrb32
31-10-2008, 23:05:51
Pues muchas gracias, x7iBiT.
Al final, el programa me ha quedado tal que así:
#!/bin/bash
if [ $# != 3 ]
then echo "No se han introducido todos los argumentos"
exit
fi
awk -F: -v i1=$1 ' {if (i1==$1) $existe = 1; else $existe = 0}
END {if ($existe==1) print "El pasajero ya existe"; else printf ("'$1':'$2':'$3'\n") >> "PASAJEROS"} ' PASAJEROS
Y, no sé por qué, lo resaltado en negrita he tenido que ponerlo, ya que si ni no se cumplía la condición, la variable existe tomaba el valor de toda la línea del fichero. Salvo eso, lo demás es similar a lo que quería.
Un saludo y gracias de nuevo.
rrb32
09-11-2008, 17:26:16
Buenas.
Pues posteo de nuevo porque sigo con problemas con los scripts.
Resulta que tengo ficheros estructurados de la siguiente forma:
<dato1,1>:<dato1,2>:...:<dato1,N>
<dato2,1>:<dato2,2>:...:<dato2,N>
.
.
.
<datoN,1>:<datoN,2>:...:<datoN,N>
Y, por ejemplo, dato2,1 es un número que he de decrementar. ¿Cómo lo hago? Con cut's y grep's consigo dato2,1 y lo guardo en una variable que después decremento, pero después no sé ponerla en el lugar donde estaba.
Esta es una duda, y ahora otra. He de mostrar por pantalla datosX,1 y datosX,N, por ejemplo, donde X es un número cualquiera y los datos han de cumplir cierta condición. Recupero las líneas que cumplan las condiciones necesarias con las columnas correspondientes, pero los datos siguen la siguiente forma <dato1,1>:<dato1,N> <dato3,1>:<dato3,N> ... ¿Cómo los muestro por pantalla de modo que sigan la siguiente forma:
<dato1,1> <dato1,N>
<dato3,1> <dato3,N>
He probado ya varias cosas, pero no se me ocurre nada.
Un saludo.
x7iBiT
09-11-2008, 22:51:08
Si estuviera en C, C++ o similar lo que yo haría es usar un array bidimensional para guardar toda la tabla. Al principio leería los elementos de fichero y lo iría guardando en el array, y al final de todo es cuando escribiría el array en el fichero. Si en el medio tengo que buscar o cambiar algo lo haría en el array (típicos dos bucles for anidados) y no en el fichero.
Ahora bien, no estoy seguro si el bash permite arrays bidimensionales (juraría que no). En el caso de efectivamente no se pueda, se podría adaptar la idea de arriba haciendo un array unidiemsional en donde cada elemento es una línea, y luego hacer uso de separadores para separar los distintos elementos de cada fila/línea.
EDITO: además de esta forma también sería bastante fácil implementar lo que comentas en tu "segunda duda". Vas recorriendo línea a línea del array (for i), validas en cada iteración la condición, y si se cumple muestras el primer elemento y el último (N) con grep por ejemplo.
rrb32
09-11-2008, 23:29:09
Bueno, pues tu idea sobre la utilización de matrices me ha hecho pensar, y, mirando un manual, he visto que no se pueden utilizar arrays bidimensionales. Sin embargo, para el segundo punto, que es el que estoy mirando ahora mismo, lo que hago es guardar cada campo en un elemento del vector, de modo que en el primer elemento tengo, por ejemplo, 01 02 03, en el segundo Barcelona Madrid Sevilla...
Ahora, para mostrar por pantalla 01 Barcelona\n02 Madrid\n03 Sevilla (\n es salto de línea), para cada elemento de la matriz he de separarlos según el espacio del elemento (01 de 02, ...), lo cual ya no sé hacer. A ver si sabes algo sobre ello, x7iBiT.
Un saludo y gracias.
x7iBiT
09-11-2008, 23:54:20
No estoy seguro de lo que quieres decir. Pero creo que lo que buscas se podría hacer con un bucle for, un índice "i" (variable numérica) que se incrementa en cada iteración, y luego esto para que te imprima sóla dicha columna (dada por la variable "i"):
awk -v i=$i '{print $i}'Así en la primera iteración imprimirá sólo la primera columna, en la segunda iteración sólo la segunda, etc.
EDITO: Para hace un bucle for tipo C, en donde hay una índice "i" que por ejemplo va de 1 a 10, sería:
for i in `seq 1 10`;
do
echo $i
done
rrb32
10-11-2008, 00:03:35
Buenas, x7iBiT.
Gracias denuevo por tu ayuda, pero no es exactamente eso lo que te pedía. Me refería a, por ejemplo, tengo en el primer elemento del array 01 02 03. En el segundo elemento del array Barcelona Madrid Sevilla. Y quiero unir 01 con Barcelona,para mostrarlo por pantalla relacionados, 02 con Madrid y 03 con Sevilla. De la manera en que está montada el array, haciedo un bucle, en la primera iteración me mostraría 01 02 03, en la segunda Barclona Madrid Sevilla... Y no es esto lo que yo quiero.
Pero ahora, tratando de resolver esto, he dado con SED, que puede resolver mi primer problema en el cual necesitaba modificar valores en los campos y eliminar según que caso líneas del fichero, de modo que ahora estoy con esto ahora. Cuando lo tenga ya contaré qué tal me ha funcionado.
Un saludo y gracias nuevamente x7iBiT.
x7iBiT
10-11-2008, 00:33:52
Si, creo que no me entendiste. Si por ejemplo la variable se llama $vector y tiene 3 elementos (por el hecho de hacer la matriz cuadrada):
vector[1]=01 02 03
vector[2]=Barcelona Madrid Sevilla
vector[3]=a b c
Y quieres mostrar:
01 Barcelona a
02 Madrid b
03 Sevilla c
Entonces sería algo así como:
for i in `seq 1 3`;
do
for j in `seq 1 3`;
do
echo "${vector[$j]}" | awk -v i=$i '{printf $i " "}'
done
printf "\n"
done
PD: Lo acabo de probar y funciona.
rrb32
10-11-2008, 12:38:29
Pues parece que sí, que te entendí mal, porque con el código que me has puesto, funciona, realizando un pequeño cambio:
for i in `seq 1 3`;
do
for j in `seq 1 3`;
do
echo ${vector[$j]} | awk -v i=$i '{printf $i " "}'
done
printf "\n"
done
es decir, quitando las comillas dobles de ${vector[$j]}, porque si no, no me lo mostraba con el salto de línea.
Un saludo y gracias nuevamente.
x7iBiT
10-11-2008, 12:59:31
Que raro que yo lo probé y si que me funcionaba con el salto de línea, y más raro todavía que nos pase teniendo exactamente la misma reproducción (y la misma rama).
Pero bueno, lo importante es que funciona :genial:
vBulletin v3.7.0, Derechos ©2000-2009, Jelsoft Enterprises Ltd.