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

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

일부 위치에 빈 파일이 있는지 확인하고 발견되면 이메일을 보내려는 bash 스크립트를 작성하려고 합니다. 처음에는 "find"와 "mail"을 합쳐서 생각해볼까 했는데, 그 위치에 빈 파일이 여러 개 있으면 여러 개의 메일을 보내게 되는 게 원하지 않는 일이니까 찾기 전에 플래그 변수를 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

쉘 내장은 ize 연산자 [ test ]와 함께 사용할 수 있습니다 -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인쇄 일치 항목을 만들고 첫 번째 줄만 유지할 수 있습니다. finda로 죽을 것이다시그파이프head파이프의 측면을 닫은 후 .

if [ -n "$(find "$LOCATION" -size 0 -type f -print | head -n 1 \;)" ]; then
  FLAG=1
else
  FLAG=0
fi

이것이 단순한 예일 뿐이고 더 복잡한 변수를 설정해야 하는 경우 몇 가지 가능한 접근 방식이 있습니다. 몇 가지 일반적인 사항만 언급하겠습니다.

findZsh에는 다음과 같은 기능이 내장되어 있어 많은 사용 사례가 있습니다 .글로벌 한정자. 다음 스니펫은 files다음과 일치하는 파일 목록으로 설정됩니다 find $LOCATION -size 0 -type f.

files=(**/*(.DL0))

set -o globstarKsh와 bash에는 및를 각각 활성화한 경우 재귀적 글로브도 있습니다 shopt -s globstar. 그러나 최대 4.2의 bash에서는 **디렉토리에 대한 기호 링크로 반복되므로 일반적으로 바람직하지 않습니다. 셸에서 추가 처리를 수행할 수 있습니다.

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
}

관련 정보