web-dev-qa-db-ja.com

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

特定のフォルダに多数のファイルがあります。これらのファイルをサブフォルダーに移動したいのは、列4のいずれかの行に0.5を超える値が少なくとも1つある場合のみです。別のコマンドで同じことを行いますが、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の0.5を超える値が少なくとも1つあるファイルを移動するためにこれまでに試したものです。条件に一致しないファイルも含め、すべてのファイルをサブフォルダーに移動することになります。

#!/bin/bash

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

3
Sarah

コマンドを機能させるには、一致が見つかった場合は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コマンドは、一度に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または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
Bodo

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
terdon

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