移动特定列的任何行中值高于阈值的文件

移动特定列的任何行中值高于阈值的文件

我在特定文件夹中有大量文件。我想将这些文件移动到子文件夹,前提是它们在第 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

相关内容