내 tldr 답변은 다음과 같습니다
function emptydir {
[ "$1/"* "" = "" ] 2> /dev/null &&
[ "$1/"..?* "" = "" ] 2> /dev/null &&
[ "$1/".[^.]* "" = "" ] 2> /dev/null ||
[ "$1/"* = "$1/*" ] 2> /dev/null && [ ! -e "$1/*" ] &&
[ "$1/".[^.]* = "$1/.[^.]*" ] 2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
[ "$1/"..?* = "$1/..?*" ] 2> /dev/null && [ ! -e "$1/..?*" ]
}
POSIX 호환이며 중요하지는 않지만 일반적으로 디렉토리를 나열하고 출력을 grep에 파이프하는 솔루션보다 빠릅니다.
용법:
if emptydir adir
then
echo "nothing found"
else
echo "not empty"
fi
나는 https://unix.stackexchange.com/a/202276/160204 대답을 좋아합니다 .
function emptydir {
! { ls -1qA "./$1/" | grep -q . ; }
}
디렉토리를 나열하고 결과를 grep으로 파이프합니다. 대신, glob 확장 및 비교에 기반한 간단한 함수를 제안합니다.
function emptydir {
[ "$(shopt -s nullglob; echo "$1"/{,.[^.],..?}*)" = "" ]
}
이 함수는 표준 POSIX가 아니며을 사용하여 서브 쉘을 호출합니다 $()
. 이 간단한 기능을 먼저 설명하여 나중에 최종 솔루션을 더 잘 이해할 수 있습니다 (위의 tldr 답변 참조).
설명:
확장이 발생하지 않으면 왼쪽 (LHS)이 비어 있습니다. 디렉토리가 비어있는 경우입니다. 일치하지 않는 경우 glob 자체가 확장의 결과이므로 nullglob 옵션이 필요합니다. (디렉토리가 비어있을 때 RHS가 LHS의 glob와 일치하는 것은 LHS glob가 glob 자체로 명명 된 단일 파일과 일치 할 때 발생하는 잘못된 긍정으로 인해 작동하지 않습니다. glob 의 파일 이름 *
의 하위 문자열과 일치합니다 *
. ) 중괄호 표현식 {,.[^.],..?}
은 숨겨진 파일을 포함하지만 ..
또는 은 포함하지 않습니다 .
.
(서브 쉘) shopt -s nullglob
내부에서 실행 되기 때문에 현재 쉘 $()
의 nullglob
옵션을 변경하지 않습니다 . 일반적으로 좋은 것입니다. 반면에 스크립트에서이 옵션을 설정하는 것이 좋습니다. 일치하지 않으면 glob이 무언가를 반환하는 경향이 있기 때문입니다. 따라서 스크립트 시작시 nullglob 옵션을 설정할 수 있으며이 기능에는 필요하지 않습니다. 이것을 명심하자 : 우리는 nullglob 옵션과 함께 작동하는 솔루션을 원한다.
주의 사항 :
디렉토리에 대한 읽기 권한이없는 경우, 함수는 빈 디렉토리가있는 것과 동일하게보고합니다. 이것은 디렉토리를 나열하고 출력을 grep하는 기능에도 적용됩니다.
이 shopt -s nullglob
명령은 표준 POSIX가 아닙니다.
로 작성된 서브 쉘을 사용합니다 $()
. 큰 문제는 아니지만 피할 수 있다면 좋습니다.
찬성:
실제로 중요하지는 않지만이 함수는 프로세스 내 커널에서 소비 한 CPU 시간으로 측정 된 이전 함수보다 4 배 빠릅니다.
다른 솔루션 :
shopt -s nullglob
LHS에서 POSIX가 아닌 명령을 제거하고 문자열 "$1/* $1/.[^.]* $1/..?*"
을 RHS에 넣을 수 있으며 이름이 '*'
, .[^.]*
또는 ..?*
디렉토리에 파일 만있을 때 발생하는 오 탐지를 별도로 제거 할 수 있습니다 .
function emptydir {
[ "$(echo "$1"/{,.[^.],..?}*)" = "$1/* $1/.[^.]* $1/..?*" ] &&
[ ! -e "$1/*" ] && [ ! -e "$1/.[^.]*" ] && [ ! -e "$1/..?*" ]
}
shopt -s nullglob
명령이 없으면 서브 쉘을 제거하는 것이 합리적이지만, 단어 분리를 피하면서 LHS에서 glob 확장을 허용하기 때문에주의해야합니다. 특히 단어 분리를 피하기위한 인용은 글롭 확장을 막기 때문에 작동하지 않습니다. 우리의 해결책은 글로브를 개별적으로 고려하는 것입니다.
function emptydir {
[ "$1/"* = "$1/*" ] 2> /dev/null && [ ! -e "$1/*" ] &&
[ "$1/".[^.]* = "$1/.[^.]*" ] 2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
[ "$1/"..?* = "$1/..?*" ] 2> /dev/null && [ ! -e "$1/..?*" ]
}
우리는 여전히 개별 glob에 대해 단어 분할을 가지고 있지만 디렉토리가 비어 있지 않을 때만 오류가 발생하기 때문에 지금은 괜찮습니다. 우리는 2> / dev / null을 추가하여 LHS에 주어진 glob과 일치하는 많은 파일이있을 때 오류 메시지를 삭제했습니다.
nullglob 옵션과 함께 작동하는 솔루션을 원한다는 것을 기억합니다. 디렉토리가 비어 있으면 LHS도 비어 있으므로 위의 솔루션은 nullglob 옵션으로 실패합니다. 다행히도 디렉토리가 비어 있지 않다면 절대로 말하지 않습니다. 그것이 비어있을 때만 말하는 것은 아닙니다. 따라서 nullglob 옵션을 별도로 관리 할 수 있습니다. 문법적으로 잘못된 등으로 [ "$1/"* = "" ]
확장되므로 사례 등을 추가 할 수 없습니다 [ = "" ]
. 그래서 우리는 [ "$1/"* "" = "" ]
대신 등을 사용합니다. 우리는 다시 세 가지 사례를 고려해야합니다 *
, ..?*
그리고 .[^.]*
숨겨진 파일과 일치 할 수 있지만 .
및..
. nullglob 옵션이 없으면 간섭하지 않습니다. 비어 있지 않다고 말하지 않기 때문입니다. 따라서 최종 제안 된 솔루션은 다음과 같습니다.
function emptydir {
[ "$1/"* "" = "" ] 2> /dev/null &&
[ "$1/"..?* "" = "" ] 2> /dev/null &&
[ "$1/".[^.]* "" = "" ] 2> /dev/null ||
[ "$1/"* = "$1/*" ] 2> /dev/null && [ ! -e "$1/*" ] &&
[ "$1/".[^.]* = "$1/.[^.]*" ] 2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
[ "$1/"..?* = "$1/..?*" ] 2> /dev/null && [ ! -e "$1/..?*" ]
}
보안 문제 :
두 개의 파일을 생성 rm
하고 x
빈 디렉토리 및 실행 *
프롬프트에. glob *
가 확장 rm x
되고이를 제거하기 위해 실행됩니다 x
. 우리의 함수에서 globs는 확장이 명령으로 보이지 않고 에서처럼 인수로 보이는 곳에 위치하기 때문에 이것은 보안상의 문제가 아닙니다 for f in *
.