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