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

Вы делаете это правильно, но синтаксис bash легко неправильно истолковать :вы можете подумать, что echo $TESTзаставляет echoизвлекать TESTenv var, а затем печатать его, но это не так. Так дано

export TEST=123

, затем

TEST=456 echo $TEST

включает следующую последовательность:

  1. Оболочка анализирует всю командную строку и выполняет все подстановки переменных, поэтому командная строка становится

    TEST=456 echo 123
    
  2. Он создает временные переменные, установленные перед командой, поэтому сохраняет текущее значение TESTи перезаписывает его на 456; командная строка теперь

    echo 123
    
  3. Он выполняет оставшуюся команду, которая в данном случае выводит 123 на стандартный вывод (, поэтому оставшаяся команда оболочки даже не использовала временное значениеTEST)

  4. Восстанавливает значениеTEST

Вместо этого используйте printenv, так как он не требует подстановки переменных:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>
3
06.04.2020, 19:56
3 ответа

Чтобы ваша команда работала, вы должны 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/ \;
3
28.04.2021, 23:18

Ваш 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
28.04.2021, 23:18

С помощью цикла 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
1
28.04.2021, 23:18

Теги

Похожие вопросы