2011-01-30 9 views
6

Necesito obtener una cadena de versión particular de un archivo (llámala version.lst) y la uso para comparar otra en un script de shell. Por ejemplo, sake, el archivo contiene líneas que se ven así:¿La mejor manera de analizar esta cadena en particular usando awk/sed?

V1.000 -- build date and other info here -- APP1 
V1.000 -- build date and other info here -- APP2 
V1.500 -- build date and other info here -- APP3 

.. y así sucesivamente. Digamos que estoy tratando de tomar la primera versión (en este caso, V1.000) de APP1. Obviamente, las versiones pueden cambiar y quiero que esto sea dinámico. Lo que tengo en este momento funciona:

var = `cat version.lst | grep " -- APP1" | grep -Eo V[0-9].[0-9]{3}` 

de tuberías a grep obtendrá la línea que contiene APP1 y el segundo tubo a grep obtendrá la cadena de versión. Sin embargo, he escuchado que grep no es la manera de hacerlo, así que me gustaría aprender la mejor forma de usar awk o sed. ¿Algunas ideas? Soy nuevo en ambos y no he encontrado un tutorial lo suficientemente fácil como para aprender la sintaxis del mismo. ¿Apoyan egrep? ¡Gracias!

Respuesta

11

Pruebe lo siguiente para obtener la versión completa:

#!/bin/sh 
app=APP1 
var=$(awk -v "app=$app" '$NF == app {print $1}' version.lst) 

o para obtener sólo el número de versión principal, la última línea podría ser:

var=$(awk -v "app=$app" '$NF == app {split($1,a,"."); print a[1]}' version.lst) 

Usando sed para conseguir la completa versión:

var=$(sed -n "/ $app\$/s/^\([^ ]*\).*/\1/p" version.lst) 

o esto para conseguir sólo el mayor número de versión:

var=$(sed -n "/ $app\$/s/^\([^.]*\).*/\1/p" version.lst) 

Explicaciones:

El segundo comando AWK:

  • -v "app=$app" - establecer una variable de AWK igual a una variable de shell
  • $NF == app - si el último campo es igual al contenido de la variable (NF es el número de campo, entonces $NF es el contenido del campo NFth)
  • {split($1,a,".") - a continuación, dividir el primer campo en el punto
  • print a[1] - e imprimir la primera parte del resultado de la división

Los sed comandos:

  • -n - no hacer imprime cualquier salida a menos que esté dirigido a
  • "/ $app\$/ - para cualquier línea que termine con (\$) el contenido de la variable de shell $app (no es que las comillas dobles se utilizan para permitir la variable que se expande y es una buena idea para escapar el segundo signo del dólar)
  • s/^\([^ ]*\).*/\1/p" - empezando por el principio de la línea (^), capturar \(\) la secuencia de caracteres que consiste en espacios no ([^ ]) (o puntos no en la segunda versión) de cualquier número (cero o más *) y coincide, pero no captura todos los demás caracteres de la línea (.*), reemplace el emparejado texto (la línea completa en este caso) con la cadena que se capturó (el número de versión) (\1 se refiere al primer grupo de captura (solo en este caso) e imprímalo (p)
+0

Gracias por las múltiples respuestas usando awk y sed (y evitando grep), miraremos las respectivas documentaciones para ver exactamente lo que están haciendo, especialmente para sed que me parece extraño. – Jack

+0

@Jack: Consulte mi respuesta editada para obtener explicaciones. –

+0

Muy apreciado señor! – Jack

3

Si he entendido bien: egrep "APP1$" version.lst | awk '{print $1}'

+0

Lo siento, olvidé mencionar que algunos de los nombres de las aplicaciones podrían superponerse, por lo que podría tener algo llamado APP1 y luego APP2_APP1 (vale, no superposición, pero otros nombres de aplicaciones podrían contener el nombre de otra aplicación), en cuyo caso creo esto imprimirá ambas versiones IIRC. Por supuesto, egrep "- APP1 $" resolvería eso, pero estoy seguro de que hay una manera más bonita de hacerlo. – Jack

+0

Solo agregaría un antes de "APP1". –

+0

Supongo que funciona entonces :) Gracias por el truco awk '{print $ 1}', eso está bien. ¿Es egrep la única forma de obtener primero la línea en cuestión? ¿Y luego sed/awk para manipularlo/filtrarlo? – Jack

1
$ awk '/^V1\.00.* APP1$/{print $NF}' version.lst 
APP1 

Esa expresión regular coincide con las líneas que comienzan con "V1.00", seguido de cualquier número de cualquier otro carácter, que termina con "APP1". La barra diagonal inversa en el medio puede ser realmente importante: solo coincide con ".", Por lo que excluye (probablemente se corrompe) las líneas que podrían comenzar con, digamos, "V1a00". El espacio antes de "APP1" excluye cosas como "APP2_APP1".

"NF" es una variable generada automáticamente que contiene el número de campo en la línea de entrada. También es el número del último campo, que es el que le interesa.

Hay un par de formas de eliminar el "V1". Aquí hay una manera, aunque tú y yo podríamos no estar hablando de lo mismo.

$ awk '/^V1\.00.* APP1$/{print substr($1, 1, index($1, ".") - 1), $NF}' version.lst 
V1 APP1 
+0

Gracias por la respuesta y la explicación de lo que hace cada operación, ayuda mucho. – Jack

Cuestiones relacionadas