llamada al sistema awk con efecto invertido

Tengo un archivo de datos con varios bloques de datos entre palabras clave específicas (DATA , END). Estoy usando awk para extraer los bloques de datos en archivos separados, basado en un nombre de archivo tomado de dicho bloque. Dado que algunos bloques de datos comparten el mismo nombre, cambiaré el nombre de cada archivo de salida con un número entero creciente si el archivo («blockname«) ya existe:

#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4 

Se espera que haya tres archivos de salida blockname1, blockname2 y blockname1_1 (observe cómo el último archivo tiene un número entero asignado)

#cat blockname1 DATA blockname1 data1 data1 END 

(los demás en consecuencia …)

Ahora el siguiente script funciona como yo quiero:

awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file 

Mi problema radica en el bucle while y su llamada al sistema:

Esperaba que system("test -e " file) fuera TRUE cuando el file existiera y fuera FALSE si file aún no existe, es decir, el bucle while solo comienza a ejecutarse si file está presente y romper si (el nuevo) file aún no existe.

Sin embargo, si uso system("test -e " file) (y hacerlo detallado con print file), tengo un bucle infinito del mismo nombre con un sufijo de entero creciente y el opuesto system("test !-e " file) da el resultado deseado.

Así que esto se comporta exactamente a la inversa de lo que esperaba.

Respuesta

OK, pensé: el problema radica en las diferentes definiciones de lo que es VERDADERO y FALSO entre el estado de salida de test y el while condición de bucle en awk.

Un comando test positivo da como resultado un código de salida de 0 para TRUE y uno negativo en 1 para FALSE.

Sin embargo, en awk el ciclo while interpreta 0 como FALSO y 1 como VERDADERO, exactamente lo contrario definición.

Como ejemplo:

awk "{ while ( 0 ) ; { print "0" } }" file 

no proporcionará duce cualquier salida, mientras que

awk "{ while (1) ; { print "1" } }" file 

imprimirá 1 s infinitas.

Mejores prácticas por lo tanto, debe ser explícito en dicha combinación

while ( system("command") == 0 ) 

o

while ( system("command") == 1 ) 

respectivamente.

Entonces en mi caso

while ( system("test -e " file ) == 0 ) 

muestra el comportamiento esperado.

Respuesta

awk system() devuelve un estado de salida del comando que ejecuta: 0 para el éxito y! = 0 si no tiene éxito. Por ejemplo, puede intentar ejecutar:

v = system("date"); 

v será 0

si ejecuta:

v = system("dat"); 

v podría ser 127 o un valor diferente de 0, el error devuelto por el sistema operativo si falta el comando dat o no se encuentra.

Respuesta

Si te entiendo, el objetivo es extraer el contenido de input.file en varios archivos evitando perder bloques con el mismo nombre.

Si ese es el caso, y, si el directorio de destino siempre está vacío antes de la extracción, entonces hay una solución mejor (y más rápida):

awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file 

De esta manera awk no «No es necesario ejecutar un nuevo shell N veces solo para probar si el archivo existe.

Notas:

  • No es necesario el bloque BEGIN, porque el separador de campo de awk ya tiene espacios.
  • No es necesario el "\" al final de las líneas, porque la comilla simple ya es de varias líneas.

Comentarios

  • Bueno, mi problema fue más en comprender el comportamiento » extraño » de la condición while. Sin embargo, su solución es bastante ordenada, gracias, prefiero esto a mi cosa voluminosa. El bloque BEGIN es un sobrante de mi formato de archivo diferente; olvidé que se vuelve inútil en mi ejemplo genérico. Dejar la barra invertida me ahorrará algunos problemas. Gracias por esto también. Pero está en lo cierto con respecto a la intención del script ‘. ¿Podría explicar la parte n = blocks[block]++; file=block (n? "_" n: "") con más detalle?
  • El algoritmo usa una matriz: blocks que está indexada por nombre de bloque. Ex. En la primera instancia de "blockname1": blocks["blockname1"]. Awk encuentra ese índice y, dado que no es ‘ t encontrado, asume "" (también se considera cero). Ahora, en awk n = var++ es equivalente a {n=var;var++}, entonces n=="" y blocks["blockname1"]==1.Por último, file=block (n? "_" n: "") es lo mismo que {file=block;if(n!="") file+="_" n}.
  • Yo no era ‘ t incluso consciente de que una cadena es una variable de indexación válida y si esta declaración if reducida es muy útil, gracias de nuevo. Estoy ‘ entristecido. No puedo darte la » respuesta aceptada » aquí: a pesar de mí. voy a adoptar este enfoque ya que cumple con mi tarea inicial, no ‘ no responde la pregunta anterior (interpretación de la condición en el ciclo while); iría en contra de mi comprensión de estos sitios. Q & Un sistema. Sin embargo, aprendí mucho, gracias de nuevo.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *