移動特定列的任何行中值高於閾值的文件

移動特定列的任何行中值高於閾值的文件

我在特定資料夾中有大量文件。我想將這些檔案移到子資料夾,前提是它們在第4 列的任何行中至少有1 個高於0.5 的值。 2 行具有上述值第 4 欄為 0.5。

這是文件的一般格式(帶標題):

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

下面的程式碼是我到目前為止嘗試移動第 4 列中至少有 1 個值高於 0.5 的檔案的程式碼。

#!/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 個符合行的文件,您可以對匹配項進行計數。

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

相關內容