쉘 스크립트에서 디렉토리에 파일이 있는지 어떻게 확인합니까?
이것과 비슷한 것
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
그러나 디렉토리에 하나 또는 여러 파일이 포함 된 경우 작동합니다 (위의 파일은 정확히 0 또는 1 파일에서만 작동합니다).
쉘 스크립트에서 디렉토리에 파일이 있는지 어떻게 확인합니까?
이것과 비슷한 것
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
그러나 디렉토리에 하나 또는 여러 파일이 포함 된 경우 작동합니다 (위의 파일은 정확히 0 또는 1 파일에서만 작동합니다).
답변:
지금까지의 솔루션은 ls
. 다음은 모든 bash 솔루션입니다.
#!/bin/bash
shopt -s nullglob dotglob # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
if 문이로 변경되어야 if [ ${#files} -gt 0 ];
하나요? 아니면 하위 셸 명령어 주변의 ()를 잊었나요? files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
이 트릭은 100 % bash
이며 하위 쉘을 호출 (스폰)합니다. 아이디어는 Bruno De Fraine에서 나 왔으며 teambob 의 의견으로 개선되었습니다 .
files=$(shopt -s nullglob dotglob; echo your/dir/*)
if (( ${#files} ))
then
echo "contains files"
else
echo "empty (or does not exist or is a file)"
fi
참고 : 빈 디렉토리와 존재하지 않는 디렉토리 사이에는 차이가 없습니다 (제공된 경로가 파일 인 경우에도).
#bash IRC 채널 에 대한 '공식' FAQ에 유사한 대안과 자세한 내용 (및 더 많은 예제)이 있습니다 .
if (shopt -s nullglob dotglob; f=(*); ((${#f[@]})))
then
echo "contains files"
else
echo "empty (or does not exist, or is a file)"
fi
[ -n "$(ls -A your/dir)" ]
이 트릭은 2007 년에 게시 된 nixCraft의 기사 에서 영감을 얻었습니다 . 2>/dev/null
출력 오류를 억제하려면 추가하십시오 "No such file or directory"
.
참조 앤드류 테일러 의 대답 (2008)와 gr8can8dian 의 대답 (2011).
if [ -n "$(ls -A your/dir 2>/dev/null)" ]
then
echo "contains files (or is a file)"
else
echo "empty (or does not exist)"
fi
또는 한 줄 bashism 버전 :
[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"
참고 : 디렉토리가 존재하지 않을 때 ls
반환 $?=2
됩니다. 그러나 파일과 빈 디렉토리 사이에는 차이가 없습니다.
[ -n "$(find your/dir -prune -empty)" ]
이 마지막 트릭은 phils 의 의견으로 대체되고 개선 된 gravstar 의 답변 에서 영감을 받았습니다 .-maxdepth 0
-prune
if [ -n "$(find your/dir -prune -empty 2>/dev/null)" ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
다음을 사용하는 변형 -type d
:
if [ -n "$(find your/dir -prune -empty -type d 2>/dev/null)" ]
then
echo "empty directory"
else
echo "contains files (or does not exist or is not a directory)"
fi
설명:
find -prune
find -maxdepth 0
적은 문자를 사용하는 것과 유사 합니다.find -empty
빈 디렉토리 및 파일을 인쇄합니다.find -type d
디렉토리 만 인쇄참고 :[ -n "$(find your/dir -prune -empty)" ]
아래의 단축 버전으로 대체 할 수도 있습니다.
if [ `find your/dir -prune -empty 2>/dev/null` ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
이 마지막 코드는 대부분의 경우에 작동하지만 악의적 인 경로가 명령을 표현할 수 있습니다.
[ -n "$(find "your/dir" -prune -empty)" ]
디렉토리 경로의 반복을 피하기 위해 찾기 옵션을으로 단순화 할 수 있다고 생각합니다 .
if [ ``ls -A your/dir`` ]
스크립트에서 사용하는 동안 0, 1 또는 2 개의 하위 디렉토리가있는 디렉토리에서는 잘 작동하지만 2 개 이상의 하위 디렉토리가있는 디렉토리에서는 실패한다는 결론에 도달했습니다. 디렉토리 이름 중 하나는 line 17: [: 20150424-002813: unary operator expected
어디에 있습니까 20150424-002813
? 사용 된 쉘은 /bin/bash/
. 나는 마지막으로 변경ls "$destination" | tail -1
if [ ``ls -A my/dir`` ]
은 오류로 종료됩니다 bash: [: -A: binary operator expected
. bash 버전 4.1.2 및 4.2.53에서 테스트되었습니다.
-n
변형이 헤드 라인에 있었지만 아래 단락 에는 없었기 때문에 ). 네, 괜찮습니다.
ls: cannot access '/path': No such file or directory
. 이 메시지를 억제 할 수있는 방법이 있습니까? 나는 거기에서 조용히 실패하고 싶다.
다음은 어떻습니까?
if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
이렇게하면 디렉토리 내용의 전체 목록을 생성 할 필요가 없습니다. (가) read
두 출력을 버리고 뭔가를 읽을 경우에만 true로 평가 식을 수 있도록하는 것입니다 (즉,은 /some/dir/
으로 비어 발견된다 find
).
find /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;
-maxdepth
및 -empty
기본 에 의존합니다 .
시험:
if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
/bin/ls <some_dir>/* 2> /dev/null
if [! -z "$ tmp"]; then echo 뭔가 있습니다 fi
ls /some/dir/*
]; 그런 다음 에코 "huzzah"; fi
-n
대신 사용할 수 있습니다 ! -z
(둘 다 동등하지만 존재하는 경우 더 짧은 형식을 사용하지 않는 이유).
BigGray% if [ ! -z
ls / some / dir / *`]; 그런 다음 에코 "huzzah"; fi zsh : 일치하는 항목이 없습니다 : / some / dir / *`
ls...
bash에서 큰 따옴표 없이는 나를 위해 작동하지 않습니다
# Works on hidden files, directories and regular files
### isEmpty()
# This function takes one parameter:
# $1 is the directory to check
# Echoes "huzzah" if the directory has files
function isEmpty(){
if [ "$(ls -A $1)" ]; then
echo "huzzah"
else
echo "has no files"
fi
}
# 디렉토리에 숨겨지지 않은 파일이 있는지 확인합니다. # # 사용법 : if isempty "$ HOME"; then echo "Welcome home"; fi # 비었다() { $ 1 / *의 _ief에 대해; 하다 if [-e "$ _ief"]; 그때 반환 1 fi 끝난 반환 0 }
구현 참고 사항 :
for
루프는 외부로 전화 방지 ls
과정을. 여전히 모든 디렉토리 항목을 한 번 읽습니다. 이것은 readdir ()을 명시 적으로 사용하는 C 프로그램을 작성해야만 최적화 할 수 있습니다.test -e
루프 내부 변수가있는 경우 빈 디렉토리의 경우 잡는다 _ief
값 "somedir / *"를 할당 할 것입니다. 해당 파일이 존재하는 경우에만 함수가 "비어 있지 않음"을 반환합니다.test
구현은 지원하지 않습니다 -e
플래그.dotglob
설정되어 있지 않습니다 -shopt -s dotglob
이것은 디렉토리가 비어 있는지 또는 비어 있지 않은 경우 포함 된 파일 수를 알려줍니다.
directory="/some/dir"
number_of_files=$(ls -A $directory | wc -l)
if [ "$number_of_files" == "0" ]; then
echo "directory $directory is empty"
else
echo "directory $directory contains $number_of_files files"
fi
ls
있기 때문 입니다 .
dir_is_empty() {
[ "${1##*/}" = "*" ]
}
if dir_is_empty /some/dir/* ; then
echo "huzzah"
fi
라는 이름의 파일이없는 가정 *
에를 /any/dir/you/check
, 그것은에 작업을해야 bash
dash
posh
busybox sh
하고 zsh
필요하지만 (zsh을 위해) unsetopt nomatch
.
성능은 (glob) ls
을 사용 하는 모든 것과 비슷해야합니다. *
노드가 많은 디렉토리에서 느릴 것이라고 생각합니다 ( /usr/bin
3000 개 이상의 파일을 사용하는 경우 그다지 느리지 않음). 최소한 모든 디렉토리 / 파일 이름을 할당 할 수있을만큼 충분한 메모리를 사용합니다. 모두 인수로 함수에 전달 (해결)되므로 일부 쉘은 인수 수 및 / 또는 인수 길이에 제한이있을 수 있습니다.
디렉토리가 비어 있는지 확인하는 이식 가능한 빠른 O (1) 제로 리소스 방법이 있으면 좋을 것입니다.
최신 정보
위의 버전 is_empty
은 Rich의 sh (POSIX shell) 트릭 과 같이 더 많은 테스트가 필요한 경우 숨겨진 파일 / 디렉터리를 고려하지 않습니다 .
is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )
그러나 대신 다음과 같은 것을 생각하고 있습니다.
dir_is_empty() {
[ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ]
}
dir이 비어있을 때 인수 및 find 출력과의 후행 슬래시 차이점과 후행 줄 바꿈 (하지만 처리하기 쉽습니다)에 대한 우려가 있습니다. 슬프게도 내 busybox
sh
쇼 find -> dd
에서 출력이 무작위로 잘린 파이프 의 버그 일 것입니다 ( 내가 사용한 cat
경우 출력은 항상 동일 dd
하며 인수가 있는 것 같습니다 count
).
is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };
나는 질문이 bash로 표시되었다는 것을 안다. 참고로 zsh 사용자의 경우 :
foo
비어 있지 않은지 확인하려면 :
$ for i in foo(NF) ; do ... ; done
만약 여기서 foo
비어 있지 상기의 코드 for
블록이 실행된다.
foo
비어 있는지 확인하려면 :
$ for i in foo(N/^F) ; do ... ; done
foo
비어 있으면 for
블록 의 코드 가 실행됩니다.
foo
위 의 디렉토리를 인용 할 필요는 없었지만 다음과 같은 경우에 그렇게 할 수 있습니다.
$ for i in 'some directory!'(NF) ; do ... ; done
디렉토리가 아니더라도 둘 이상의 객체를 테스트 할 수도 있습니다.
$ mkdir X # empty directory
$ touch f # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done # echo empty directories
X
디렉토리가 아닌 것은 무시됩니다.
globbing이므로 어떤 glob (또는 중괄호 확장)도 사용할 수 있습니다.
$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf # create regular file
$ touch X1/f # directory X1 is not empty
$ touch Y1/.f # directory Y1 is not empty
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo # print empty directories
X X2 Y Y2
배열에 배치 된 객체를 검사 할 수도 있습니다. 위와 같은 디렉토리로 예를 들면 다음과 같습니다.
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*) # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z
따라서 배열 매개 변수에 이미 설정되어있을 수있는 객체를 테스트 할 수 있습니다.
for
블록 의 코드는 분명히 모든 디렉토리에서 차례로 실행됩니다. 이것이 바람직하지 않은 경우 단순히 배열 매개 변수를 채운 다음 해당 매개 변수에 대해 작업 할 수 있습니다.
$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories
zsh 사용자의 경우 "full"(비어 있지 않은) 디렉토리와 일치 하는 (F)
glob 한정자 (참조 man zshexpn
)가 있습니다.
$ mkdir X Y
$ touch Y/.f # Y is now not empty
$ touch f # create a regular file
$ ls -dF * # list everything in the current directory
f X/ Y/
$ ls -dF *(F) # will list only "full" directories
Y/
한정자 (F)
는 다음과 일치하는 객체를 나열합니다. 디렉토리이고 비어 있지 않습니다. 따라서 (^F)
일치 : 디렉토리가 아니거나 비어 있습니다. 따라서 (^F)
예를 들어 혼자서도 일반 파일을 나열합니다. 따라서 zshexp
man 페이지 에 설명 된대로 (/)
디렉토리 만 나열 하는 glob 한정자 가 필요합니다 .
$ mkdir X Y Z
$ touch X/f Y/.f # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z
따라서 주어진 디렉토리가 비어 있는지 확인하려면 다음을 실행할 수 있습니다.
$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished
비어 있지 않은 디렉토리가 캡처되지 않도록합니다.
$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished
이런! Y
이 비어 있지 않기 때문에 zsh는 (/^F)
( "비어있는 디렉토리")와 일치하는 항목이 없으므로 glob에 일치하는 항목이 없다는 오류 메시지를 표시합니다. 따라서 (N)
glob 한정자를 사용하여 이러한 가능한 오류 메시지를 억제해야합니다 .
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
따라서 빈 디렉토리의 경우 다음 (N/^F)
과 같이 읽을 수 있는 한정자가 필요합니다 . "충분하지 않은 디렉토리, 실패에 대해 경고하지 마십시오".
마찬가지로, 비어 있지 않은 디렉토리의 경우에는 (NF)
"실패, 전체 디렉토리에 대해 경고하지 않음"과 같이 읽을 수 있는 한정자가 필요합니다 .
빈 디렉토리에 대한 모직 가이드 가 언급되지 않은 것에 놀랐습니다 . 이 가이드와 모든 wooledge는 실제로 쉘 유형 질문에 대해 반드시 읽어야합니다.
해당 페이지에서 주목할 사항 :
ls 출력을 구문 분석하지 마십시오. ls -A 솔루션조차도 망가질 수 있습니다 (예 : HP-UX에서 루트 인 경우 ls -A는 루트가 아닌 경우 수행하는 작업과 정반대를 수행합니다. 그리고 아니요, 믿을 수 없을 정도로 구성 할 수 없습니다. 바보).
사실 직접적인 질문을 아예 피하고 싶을 수도 있습니다. 일반적으로 사람들은 디렉토리가 비어 있는지 여부를 알고 싶어합니다. 그 이유는 파일과 관련된 작업을 수행하기 때문입니다. 더 큰 질문을보십시오. 예를 들어 다음 찾기 기반 예제 중 하나가 적절한 솔루션이 될 수 있습니다.
# Bourne
find "$somedir" -type f -exec echo Found unexpected file {} \;
find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \; # GNU/BSD
find "$somedir" -type d -empty -exec cp /my/configfile {} \; # GNU/BSD
가장 일반적으로 필요한 것은 다음과 같습니다.
# Bourne
for f in ./*.mpg; do
test -f "$f" || continue
mympgviewer "$f"
done
즉, 질문을하는 사람은 mympgviewer와 같은 오류 메시지를 피하기 위해 명시적인 빈 디렉토리 테스트가 필요하다고 생각했을 수 있습니다. ./*.mpg : 실제로 그러한 테스트가 필요하지 않은 경우 그러한 파일이나 디렉토리가 없습니다.
Bruno의 대답의 작은 변형 :
files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ]
then
echo "Contains files"
else
echo "Empty"
fi
그것은 나를 위해 작동합니다
olibre의 답변에서 힌트 (또는 여러 가지)를 취하면 Bash 기능이 좋습니다.
function isEmptyDir {
[ -d $1 -a -n "$( find $1 -prune -empty 2>/dev/null )" ]
}
하나의 하위 셸을 생성하는 동안 내가 상상할 수있는 한 O (1) 솔루션에 가깝고 이름을 지정하면 읽을 수 있기 때문입니다. 그런 다음 쓸 수 있습니다
if isEmptyDir somedir
then
echo somedir is an empty directory
else
echo somedir does not exist, is not a dir, is unreadable, or is not empty
fi
O (1)의 경우 특이한 경우가 있습니다. 큰 디렉토리에 마지막 항목이 삭제 된 경우를 제외하고 모두 또는 모두가있는 경우 "find"는 비어 있는지 여부를 확인하기 위해 전체를 읽어야 할 수 있습니다. 예상 성능은 O (1)이라고 생각하지만 최악의 경우 디렉토리 크기가 선형입니다. 나는 이것을 측정하지 않았다.
지금까지 나는 더 간단한 대답을 줄 것이라고 생각하는 grep을 사용하는 대답을 보지 못했습니다 (이상한 기호가 너무 많지 않습니다!). 다음은 bourne 셸을 사용하여 디렉토리에 파일이 있는지 확인하는 방법입니다.
이것은 디렉토리의 파일 수를 반환합니다.
ls -l <directory> | egrep -c "^-"
디렉토리가 작성된 디렉토리 경로를 채울 수 있습니다. 파이프의 전반부는 출력의 첫 문자가 각 파일에 대해 "-"임을 확인합니다. 그런 다음 egrep은 정규식을 사용하여 해당 기호로 시작하는 줄 수를 계산합니다. 이제 얻은 숫자를 저장하고 다음과 같은 역 따옴표를 사용하여 비교하기 만하면됩니다.
#!/bin/sh
fileNum=`ls -l <directory> | egrep -c "^-"`
if [ $fileNum == x ]
then
#do what you want to do
fi
x는 원하는 변수입니다.
bash에 대한 간단한 대답 :
if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
나는 갈 것이다 find
:
if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
echo "$dir has NO files"
else
echo "$dir has files"
이것은 하위 디렉토리를 거치지 않고 디렉토리에서 파일 만 찾는 출력을 확인합니다. 그런 다음 다음 -z
에서 가져온 옵션을 사용하여 출력을 확인합니다 man test
.
-z STRING
the length of STRING is zero
몇 가지 결과보기 :
$ mkdir aaa
$ dir="aaa"
빈 디렉토리 :
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
그냥 dirs :
$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
디렉토리의 파일 :
$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile
하위 디렉토리의 파일 :
$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
nullglob
하면이 ls
명령 을 사용하지 않도록주의하십시오 . 그러면 명령이 성공할 것입니다.
명령 찾기로 시도하십시오. 하드 코딩 된 디렉토리 또는 인수로 지정하십시오. 그런 다음 찾기를 시작하여 디렉토리 내의 모든 파일을 검색합니다. 찾기의 반환이 null인지 확인하십시오. 찾기의 데이터를 에코
#!/bin/bash
_DIR="/home/user/test/"
#_DIR=$1
_FIND=$(find $_DIR -type f )
if [ -n "$_FIND" ]
then
echo -e "$_DIR contains files or subdirs with files \n\n "
echo "$_FIND"
else
echo "empty (or does not exist)"
fi
ls - A
게시 된 솔루션이 마음에 들지 않습니다 . 삭제를 원하지 않기 때문에 디렉토리가 비어 있는지 테스트하고 싶을 것입니다. 다음은 그렇게합니다. 그러나 빈 파일을 기록하고 싶다면 파일을 삭제하고 다시 만드는 것이 가능한 무한한 파일을 나열하는 것보다 빠릅니다.
이것은 작동합니다 ...
if ! rmdir ${target}
then
echo "not empty"
else
echo "empty"
mkdir ${target}
fi
${target}/..
.
나를 위해 잘 작동합니다 (dir이 존재할 때).
some_dir="/some/dir with whitespace & other characters/"
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
전체 확인 :
if [ -d "$some_dir" ]; then
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; else "Dir is NOT empty" fi
fi