Переместить файлы, имеющие значение выше порогового значения в любой строке определенного столбца

Переместить файлы, имеющие значение выше порогового значения в любой строке определенного столбца

У меня есть большое количество файлов в определенной папке. Я хотел бы переместить эти файлы в подпапку ТОЛЬКО ЕСЛИ они имеют хотя бы 1 значение выше 0,5 в любой строке столбца 4. В отдельной команде я хотел бы сделать то же самое, но с файлами, имеющими хотя бы 2 строки со значениями выше 0,5 в столбце 4.

Вот общий формат файлов (с заголовком):

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

Некоторые числа в столбце 4 представлены в экспоненциальном формате: 8.934553871039306e-05

Приведенный ниже код — это то, что я пробовал до сих пор, чтобы переместить файлы, в которых хотя бы 1 значение больше 0,5 в столбце 4. В итоге он перемещает все файлы в подпапку, даже те, которые не соответствуют условию.

#!/bin/bash

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

решение1

Чтобы ваша команда сработала, вам необходимо выполнить awkвыход с кодом 0, если совпадение найдено, или с ненулевым кодом выхода, если совпадений не найдено.

Кроме того, следует пропустить первую строку, поскольку нечисловое значение будет сравниваться как строка, что может привести к неожиданному совпадению.

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

Примечание: Если awkскрипт вызывается с более чем одним файлом, код выхода означает, что совпадение было найдено в любом из файлов. Команда findгарантирует, что только один файл за раз будет передан в awk, так что здесь это не проблема.

2-е редактирование:

Чтобы выбрать файлы, в которых есть как минимум 2 совпадающие строки, можно подсчитать совпадения.

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

Редактировать:

Чтобы устранить проблему, связанную с тем, что скрипт перемещает файлы, не имеющие совпадающего значения в столбце 4, можно добавить в awkскрипт код для вывода информации о совпадающей строке. Следующий код выведет имя файла, номер строки и совпадающую строку, если совпадение будет найдено.

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

Вы получите что-то вроде

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

Я предлагаю сделать это в первую очередь, чтобы найти причину проблемы.

Если есть строки, которые имеют нечисловой текст в столбце 4, значения будут сравниваться как текст. Это приведет, например, к тому, "abc"что будет больше, чем "0.5".

Другой возможной причиной может быть строка, в которой в столбце 1 или 2 есть пробелы, что приведет к неправильному распределению текста по столбцам.

Если в столбце 4 есть нечисловые значения и вы хотите игнорировать эти строки, вы можете принудительно задать числовую интерпретацию, добавив значение, 0как в 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/ \;

Если причина проблемы в том, что ваши поля разделены табуляцией и значения могут содержать пробелы, вы можете указать разделитель полей ( -F "\t"). Следующий скрипт объединяет это с другими изменениями.

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

решение2

На самом деле это awkне работает, он найдет все файлы, потому что строка col4удовлетворяет условию >=0.5:

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

Поэтому вам нужно пропустить заголовок. Вам также нужно сказать awk, чтобы он завершился успешно, если файл соответствует вашим критериям, и неудачно, если нет. Что-то вроде этого:

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

решение3

С циклом for вы можете попробовать это:

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

И для двух значений:

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

Связанный контент