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.
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 parten = blocks[block]++; file=block (n? "_" n: "")
con más detalle?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 awkn = var++
es equivalente a{n=var;var++}
, entoncesn==""
yblocks["blockname1"]==1
.Por último,file=block (n? "_" n: "")
es lo mismo que{file=block;if(n!="") file+="_" n}
.