データはなく、ヘッダーのみを持つファイルを削除する

データはなく、ヘッダーのみを持つファイルを削除する

ヘッダーだけがあり、データのないファイルを削除したいと思います。以下のコマンドを試しましたが、正常に動作します。唯一の問題は、終了状態が0でなければならず、終了状態が1であることです。

wc -l /Path/File_*  | while read CNT FN; do [ $CNT -lt 2 ] && [  "$FN" != total ] && rm "$FN"; done

Datastage ETLツールでこのコマンドを実行していますが、操作は失敗します。

終了ステータスがゼロになるようにコマンドを変更する方法はありますか?

答え1

ファイル全体を読み取る必要がないように(たとえば、wcこの操作)、ファイルの最初の行の後に少なくとも2行があることがわかっている場合は、次のようにします(GNUシステムで)。

LC_ALL=C gawk -v ORS='\0' '
  FNR == 2 {nextfile}
  ENDFILE  {if (FNR < 2) print FILENAME}' /path/File_* |
  xargs -r0 rm -f

これは、実行される命令の数を最小限に抑えるので、より効率的です。

任意のファイル名で動作するので、より安定しています。

ベースのソリューションとの機能的な違いは、wc区切られた行と区別されていない行を含むファイルを削除しないことです。

ファイルは、削除できない場合にのみ(そして最初から存在する場合)、ゼロ以外の終了状態を返します。


問題は、パイプの終了状態がパイプの右端のコマンドの終了状態であることです(オプションを使用しない限りpipefail)。

ここで一番右のコマンドはwhileループです。ループの終了状態は、ループで実行された最後のコマンドの終了状態です。時事通信。あなたの場合は、入力の最後の行で実行されるコマンドになり[ "$FN" != total ]、ファイルが1つしかない場合を除いて0ではありません/path/File_*(この場合、wc合計は印刷されません)。

次のように変更すると:

[ "$CNT" -gt 1 ] || [ "$FN" = total ] || rm -f -- "$FN"

最後の場合にのみ、ゼロ以外の終了状態を取得します。ヘッダーファイルを削除できません。

答え2

falseループが終了すると、条件が返されます。

# false           # false              = false
[ $CNT -lt 2 ] && [  "$FN" != total ]

たとえば、wc -l /path戻ると

2 total

その後、コマンドを実行します。

                                 # true           # true              = true
wc -l *  | while read CNT FN; do [ $CNT = 2 ] && [  "$FN" = total ] && echo $CNT "$FN"; done
echo $?
0

しかし、あなたが走った場合

                                 # false           # true              = false
wc -l *  | while read CNT FN; do [ $CNT = 3 ] && [  "$FN" = total ] && echo $CNT "$FN"; done
echo $?  
1

言い換えれば:

#false         # false      = false
[ 2 -eq 3 ] && [ bar = foo ]
echo $?
1

#true         # false      = false
[ 3 -eq 3 ] && [ bar = foo ]
echo $?
1

# false         # true      = false
[ 2 -eq 3 ] && [ foo = foo ]
echo $?
1

# true         # true      = true
[ 3 -eq 3 ] && [ foo = foo ]
echo $?
0

whileループの代わりにforループを使用し、一致するものがない場合は値を返す関数を使用します。

foo() {
  ret=1 # no matches found
  for file in *.txt; do # your extension
    [[ $(wc -l "$file" | cut -d' ' -f1) -eq 1 ]] && echo "rm $file" && ret=0
  done
  return $ret
}

関連情報