Mover archivos que tengan un valor superior a un umbral en cualquier fila de una columna específica

Mover archivos que tengan un valor superior a un umbral en cualquier fila de una columna específica

Tengo una gran cantidad de archivos en una carpeta en particular. Me gustaría mover estos archivos a una subcarpeta SÓLO SI tienen al menos 1 valor superior a 0,5 en cualquier fila de la columna 4. En un comando separado me gustaría hacer lo mismo pero con archivos que tengan al menos 2 filas con valores superiores 0,5 en la columna 4.

Este es el formato general de los archivos (con encabezado):

col1  col2  col3  col4  col5  col6
ABC   DEF   5.10  0.94  GHI   JKL
MNO   PQR   8.31  0.37  STU   VWX
ABC   DEF   6.49  0.84  GHI   JKL
MNO   PQR   3.32  0.21  STU   VWX

Algunos de los números de la columna 4 están en notación científica: 8.934553871039306e-05

El siguiente código es lo que he intentado hasta ahora para mover archivos con al menos 1 valor superior a 0,5 en la columna 4. Termina moviendo todos los archivos a la subcarpeta, incluso aquellos que no coinciden con la condición.

#!/bin/bash

find . -type f -exec awk '$4 >= 0.5' {} \; -exec mv -n {} ./NewFolder/ \;

Respuesta1

Para que su comando funcione, debe awksalir con el código 0 si se encuentra una coincidencia o con un código de salida distinto de cero si no se encuentra ninguna coincidencia.

Además de esto, debes omitir la primera línea porque un valor no numérico se comparará como una cadena, lo que puede generar una coincidencia inesperada.

find . -type f -exec awk 'FNR==1 {next} $4 >= 0.5 {found=1; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;

Nota: Si awkse llama al script con más de un archivo, el código de salida significa que se encontró una coincidencia en cualquiera de los archivos. El findcomando se asegurará de que solo se pase un archivo a la vez awk, por lo que esto no es un problema aquí.

2da edición:

Para seleccionar archivos que tengan al menos 2 filas coincidentes, puede contar las coincidencias.

find . -type f -exec awk 'FNR==1 {next} $4 >= 0.5 {found++; if(found >= 2) exit} END {exit found >= 2}' {} \; -exec mv -n {} ./NewFolder/ \;

Editar:

Para depurar el problema de que el script mueve archivos que no tienen un valor coincidente en la columna 4, puede agregar código al awkscript para imprimir información sobre la línea coincidente. El siguiente código imprimirá el nombre del archivo, el número de línea y la línea coincidente si se encuentra una coincidencia.

find . -type f -exec awk 'FNR==1 {next} $4 >= 0.5 {found=1; printf "%s:%d:%s\n", FILENAME, FNR, $0; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;

Obtendrás algo como

threshold.txt:2:ABC   DEF   5.10  0.94  GHI   JKL

Sugiero hacer esto primero para encontrar la causa del problema.

Si hay líneas que tienen un texto no numérico en la columna 4, los valores se compararán como texto. Esto daría como resultado, por ejemplo, "abc"un valor mayor que "0.5".

Otra posible causa podría ser una línea que tenga espacios en la columna 1 o 2, lo que provocará una asignación incorrecta del texto a las columnas.

En caso de que haya valores no numéricos en la columna 4 y desee ignorar estas líneas, puede forzar una interpretación numérica agregando el valor como 0en 0 + $4.

find . -type f -exec awk 'FNR==1 {next} 0 + $4 >= 0.5 {found=1; printf "%s:%d:%s\n", FILENAME, FNR, $0; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;

Si el motivo del problema es que sus campos están separados por una tabulación y los valores pueden contener espacios, puede especificar el separador de campo ( -F "\t"). El siguiente script combina esto con las otras modificaciones.

find . -type f -exec awk -F "\t" 'FNR==1 {next} 0 + $4 >= 0.5 {found=1; printf "%s:%d:%s\n", FILENAME, FNR, $0; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;

Respuesta2

En awkrealidad, no funciona, encontrará todos los archivos porque la cadena col4satisface >=0.5:

$ echo col4 | awk '$1>=0.5'
col4

Entonces debes saltarte el encabezado. También debe decirle a awk que salga con éxito si el archivo coincide con sus criterios y con error si no es así. Algo como esto:

find . -type f \
    -exec awk -va=1 '{ if($4 >= 0.5 && NR>1){a=0}} END{exit a}' {} \; \
    -exec mv -n {} ./NewFolder/ \;

Respuesta3

Con un bucle for puedes probar esto:

for i in *; do # *.extension
  [[ -f "$i" && $(awk 'NR>1 && $4 >= 0.5' "$i") ]] && mv "$i" NewFolder/
done

Y para dos valores:

for i in *; do  # *.extension
  [[ -f "$i" ]] && [[ $(awk 'NR>1 && $4 >= 0.5' "$i" | wc -l) -ge 2 ]] 
  mv "$i" NewFolder
done

información relacionada