find+exec를 통해 변수를 설정하는 방법은 무엇입니까?

find+exec를 통해 변수를 설정하는 방법은 무엇입니까?

특정 위치에 빈 파일이 있는지 찾아보고 발견되면 이메일을 보내는 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내에서 수행 됩니다. 프로세스의 환경은 상위 프로세스로 다시 복사되지 않습니다. 단순히 환경 변수를 설정하고 종료하는 쉘 프로세스는 지속적인 작업을 완료하지 않습니다.shfind

일치하는 파일이 있는지 테스트하려면 find출력이 비어 있는지 간단히 테스트하면 됩니다. 비어 있지 않음을 증명한 후에 파일을 삭제하기 위해 긴 파일 목록을 생성하는 것을 방지하려면 find먼저 출력을 잘라낼 수 있습니다. GNU find에는 -quit단일 문자도 표시하도록 쉽게 알 수 있는 조건자가 있습니다. 다음 코드 조각에서 FLAG일치하는 항목이 없으면 결과는 비어 있습니다.

FLAG=$(find "$LOCATION" -size 0 -type f -printf 1 -quit \;)

다음 변수는 FLAG0 또는 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 globstarKsh와 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
}

관련 정보