데이터는 없고 헤더만 있는 파일 삭제

데이터는 없고 헤더만 있는 파일 삭제

헤더만 있고 데이터가 없는 파일을 삭제하고 싶습니다. 아래 명령을 시도했는데 제대로 작동합니다. 유일한 문제는 종료 상태가 0이어야 하는데 종료 상태가 1이라는 것입니다.

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

Datastage ETL 도구에서 이 명령을 실행하고 있는데 작업이 실패합니다.

종료 상태가 0이 되도록 명령을 수정하는 방법이 있습니까?

답변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구분된 줄과 구분되지 않은 줄이 포함된 파일을 삭제하지 않는다는 것입니다.

파일은 삭제할 수 없는 경우에만(그리고 처음부터 존재하는 경우) 0이 아닌 종료 상태를 반환합니다.


문제는 파이프의 종료 상태가 파이프의 가장 오른쪽 명령의 종료 상태라는 것입니다(해당 옵션을 사용하지 않는 한 pipefail).

여기서 가장 오른쪽 명령은 whileloop입니다. 루프의 종료 상태는 루프에서 실행된 마지막 명령의 종료 상태입니다.회보. 귀하의 경우 입력의 마지막 줄에서 실행되는 명령이 될 것이며 [ "$FN" != total ], 파일이 하나만 있는 경우를 제외하고는 0이 아닙니다 /path/File_*(이 경우 wc총계는 인쇄되지 않습니다).

다음과 같이 변경하면:

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

마지막 경우에만 0이 아닌 종료 상태를 얻게 됩니다.머리글파일을 삭제할 수 없습니다.

답변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
}

관련 정보