У меня есть большое количество файлов в определенной папке. Я хотел бы переместить эти файлы в подпапку ТОЛЬКО ЕСЛИ они имеют хотя бы 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