헤더만 있고 데이터가 없는 파일을 삭제하고 싶습니다. 아래 명령을 시도했는데 제대로 작동합니다. 유일한 문제는 종료 상태가 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
).
여기서 가장 오른쪽 명령은 while
loop입니다. 루프의 종료 상태는 루프에서 실행된 마지막 명령의 종료 상태입니다.몸회보. 귀하의 경우 입력의 마지막 줄에서 실행되는 명령이 될 것이며 [ "$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
}