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 awk
sair 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 awk
script 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 find
comando 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 awk
script 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 0
em 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 awk
verdade, não funciona, ele encontrará todos os arquivos porque a string col4
satisfaz >=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