特定の列の任意の行でしきい値を超える値を持つファイルを移動する

特定の列の任意の行でしきい値を超える値を持つファイルを移動する

特定のフォルダーに多数のファイルがあります。列 4 の任意の行に 0.5 を超える値が少なくとも 1 つある場合にのみ、これらのファイルをサブフォルダーに移動したいと思います。別のコマンドで、列 4 に 0.5 を超える値が少なくとも 2 行あるファイルに対して同じ操作を実行したいと思います。

ファイルの一般的な形式は次のとおりです (ヘッダー付き)。

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 に 0.5 を超える値が少なくとも 1 つあるファイルを移動するためにこれまで試したものです。条件に一致しないファイルも含め、すべてのファイルがサブフォルダーに移動されます。

#!/bin/bash

find . -type f -exec awk '$4 >= 0.5' {} \; -exec mv -n {} ./NewFolder/ \;

答え1

awkコマンドを機能させるには、一致が見つかった場合はコード 0 で終了し、一致が見つからない場合は 0 以外の終了コードで終了する必要があります。

さらに、数値以外の値は文字列として比較され、予期しない一致につながる可能性があるため、最初の行をスキップする必要があります。

find . -type f -exec awk 'FNR==1 {next} $4 >= 0.5 {found=1; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;

注:awkスクリプトが複数のファイルで呼び出された場合、終了コードはいずれかのファイルで一致が見つかったことを意味します。コマンドは、find一度に 1 つのファイルのみが に渡されるようにする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 つの原因としては、行の列 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

2 つの値の場合:

for i in *; do  # *.extension
  [[ -f "$i" ]] && [[ $(awk 'NR>1 && $4 >= 0.5' "$i" | wc -l) -ge 2 ]] 
  mv "$i" NewFolder
done

関連情報