Mover arquivos com valor acima de um limite em qualquer linha de uma coluna específica

Mover arquivos com valor acima de um limite em qualquer linha de uma coluna específica

Tenho um grande número de arquivos em uma pasta específica. Gostaria de mover esses arquivos para uma subpasta SOMENTE SE eles tiverem pelo menos 1 valor acima de 0,5 em qualquer linha da coluna 4. Em um comando separado, gostaria de fazer o mesmo, mas com arquivos com pelo menos 2 linhas com valores acima 0,5 na coluna 4.

Este é o formato geral dos arquivos (com cabeçalho):

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

Alguns dos números da coluna 4 estão em notação científica: 8.934553871039306e-05

O código abaixo é o que tentei até agora para mover arquivos com pelo menos 1 valor acima de 0,5 na coluna 4. Acaba movendo todos os arquivos para a subpasta, mesmo aqueles que não correspondem à condição.

#!/bin/bash

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

Responder1

Para fazer seu comando funcionar, você deve awksair com o código 0 se uma correspondência for encontrada ou com um código de saída diferente de zero se nenhuma correspondência for encontrada.

Além disso, você deve pular a primeira linha porque um valor não numérico será comparado como uma string, o que pode levar a uma correspondência inesperada.

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

Nota: Se o awkscript for chamado com mais de um arquivo, o código de saída significa que uma correspondência foi encontrada em qualquer um dos arquivos. O findcomando garantirá que apenas um arquivo por vez seja passado para awk, portanto, isso não é um problema aqui.

2ª edição:

Para selecionar arquivos que possuem pelo menos 2 linhas correspondentes, você pode contar as correspondências.

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 o problema de o script mover arquivos que não possuem um valor correspondente na coluna 4, você pode adicionar código ao awkscript para imprimir informações sobre a linha correspondente. O código a seguir imprimirá o nome do arquivo, o número da linha e a linha correspondente se uma correspondência for encontrada.

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/ \;

Você obterá algo como

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

Sugiro fazer isso primeiro para encontrar a causa do problema.

Caso existam linhas que possuam texto não numérico na coluna 4, os valores serão comparados como texto. Isto resultaria, por exemplo, em "abc"ser maior que "0.5".

Outra causa possível pode ser uma linha que contenha espaços na coluna 1 ou 2, o que levará a uma atribuição errada do texto às colunas.

Caso existam valores não numéricos na coluna 4 e você queira ignorar essas linhas, você pode forçar uma interpretação numérica adicionando o valor como 0em 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/ \;

Se o motivo do problema for que seus campos estão separados por uma tabulação e os valores podem conter espaços, você pode especificar o separador de campos ( -F "\t"). O script a seguir combina isso com as outras modificações.

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/ \;

Responder2

Na awkverdade, não funciona, ele encontrará todos os arquivos porque a string col4satisfaz >=0.5:

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

Então você precisa pular o cabeçalho. Você também precisa dizer ao awk para sair com sucesso se o arquivo corresponder aos seus critérios e com falha se não corresponder. Algo assim:

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

Responder3

Com um loop for você pode tentar isso:

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

E para dois valores:

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

informação relacionada