특정 위치에 빈 파일이 있는지 찾아보고 발견되면 이메일을 보내는 bash 스크립트를 작성하려고 합니다. 처음에는 "찾기"와 "메일"을 결합하려고 생각했지만 해당 위치에 빈 파일이 여러 개 있으면 원하지 않는 메일이 여러 개 전송되므로 찾아서 설정하기 전에 플래그를 넣는 것을 생각했습니다. 변수는 다음에서 설정됩니다. 0부터 1까지이며 빈 파일이 있는지 확인하기 위해 검색이 수행됩니다. 내가 시도한 것은 다음과 같습니다.
FLAG=0
find $LOCATION -size 0 -type f -exec sh -c 'export FLAG=1' \;
echo $FLAG
그런데 문제는 해당 위치에 빈 파일이 있어도 플래그 값이 1로 바뀌지 않는다는 점이다. 내가 뭘 잘못했나요?
답변1
set -- "${LOCATION}/"*
while [ -s "$1" ] ; do shift ; done
[ -e "$1" ] && FLAG=1
쉘 내장 명령은 [ test ]
ize 연산자와 함께 사용할 수 있습니다 -s
. 에서 man test
:
-s FILE
FILE
존재하며 크기가 0보다 큽니다.
하지만 재귀적 검색에서는 이것이 쉽지 않습니다.
find
예, 하지만 부울 값을 설정하는 것처럼 간단한 작업의 경우 실제로는 이 경우에는 적합하지 않습니다. ls
재귀 검색도 마찬가지로 빠르게 수행할 수 있고 파일 크기를 목록의 첫 번째 필드로 제공하도록 쉽게 구성할 수 있으며 한 줄에 하나의 항목만 나열하도록 보장됩니다. 재귀 파일 목록에 크기가 0인 파일이 포함되어 있는지 여부에 따라 쉘 변수의 부울 값을 설정하려는 경우 이것이 ls
최선의 선택입니다 find
. 이는 상황을 복잡하게 할 뿐입니다. 관심 있는 것은 파일 위치가 아니라 파일 속성입니다. 그것이 ls
빛을 발하는 곳이고 grep
출력을 핑하는 것은 매우 쉽습니다.
이 작업은 쉽게 수행할 수 있습니다.
ls -1aqRsp "$LOCATION" 2>&1 | grep -qv "^ *[^0]\|/"
FLAG=$(($?==0))
이는 파일이 다음 FLAG
과 같은 경우 에만 설정됩니다.1
숨겨진 .dot
포함된 파일 - $LOCATION
해당 하위 디렉터리 중 하나에 존재하며 크기가 0입니다. 그렇지 않으면 $FLAG
그렇습니다 0
.
답변2
find
이렇게 하면 새로운 하위 프로세스가 분기됩니다 -exec
. 어떤 하위 프로세스도 상위 프로세스의 환경을 변경할 수 없습니다.
find
문제의 파일 이름을 수집 한 다음 두 번째 단계에서 원하는 이메일을 생성하는 것을 고려할 수 있습니다 .
find . -type f -size 0 -print >> /var/tmp/find.sz0
...
답변3
이는 호출 인스턴스 export FLAG=1
내에서 수행 됩니다. 프로세스의 환경은 상위 프로세스로 다시 복사되지 않습니다. 단순히 환경 변수를 설정하고 종료하는 쉘 프로세스는 지속적인 작업을 완료하지 않습니다.sh
find
일치하는 파일이 있는지 테스트하려면 find
출력이 비어 있는지 간단히 테스트하면 됩니다. 비어 있지 않음을 증명한 후에 파일을 삭제하기 위해 긴 파일 목록을 생성하는 것을 방지하려면 find
먼저 출력을 잘라낼 수 있습니다. GNU find에는 -quit
단일 문자도 표시하도록 쉽게 알 수 있는 조건자가 있습니다. 다음 코드 조각에서 FLAG
일치하는 항목이 없으면 결과는 비어 있습니다.
FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)
다음 변수는 FLAG
0 또는 1로 설정됩니다.
FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)
[ -n "$FLAG" ] || FLAG=0
이식성을 유지하려면 find
인쇄 일치를 수행하고 첫 번째 줄만 유지하면 find
됩니다 .신호 파이프라인head
파이프의 한쪽을 닫은 후.
if [ -n "$(find "$LOCATION" -size 0 -type f -print | head -n 1 \;)" ]; then
FLAG=1
else
FLAG=0
fi
이것이 단순한 예일 뿐이고 더 복잡한 변수를 설정해야 하는 경우 몇 가지 가능한 접근 방식이 있습니다. 몇 가지 일반적인 사항만 언급하겠습니다.
Zsh에는 다음 find
과 같은 기능이 내장되어 있습니다.글로벌 예선. 다음 코드 조각은 files
일치하는 파일 목록을 설정합니다 find $LOCATION -size 0 -type f
.
files=(**/*(.DL0))
set -o globstar
Ksh와 bash도 각각 사용되고 활성화된 경우 재귀적 글로브를 갖습니다 shopt -s globstar
. 그러나 bash가 버전 4.2에 도달하면 **
디렉토리의 심볼릭 링크로 재귀하므로 일반적으로 권장되지 않습니다. 셸에서 추가 처리를 수행할 수 있습니다.
FIGNORE= # include dot files in wildcard matches (the ksh way)
GLOBIGNORE=.:.. # include dot files in wildcard matches (the bash way)
for x in **/*; do
done
일치하는 파일 이름에 줄 바꿈이 포함되어 있지 않으면 출력을 find
줄 바꿈으로 구분된 목록으로 구문 분석할 수 있습니다.
find "$LOCATION" -size 0 -type f ! -name '*
*' -print | {
while read -r empty_file; do
…
done
}