Programming

디렉토리에 파일이 포함되어 있는지 쉘 스크립트에서 확인

procodes 2020. 8. 10. 20:32
반응형

디렉토리에 파일이 포함되어 있는지 쉘 스크립트에서 확인


쉘 스크립트에서 디렉토리에 파일이 있는지 어떻게 확인합니까?

이것과 비슷한 것

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 -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 -prunefind -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

이 마지막 코드는 대부분의 경우에 작동하지만 악의적 인 경로가 명령을 표현할 수 있습니다.


다음은 어떻습니까?

if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

이렇게하면 디렉토리 내용의 전체 목록을 생성 할 필요가 없습니다. (가) read두 출력을 버리고 뭔가를 읽을 경우에만 true로 평가 식을 수 있도록하는 것입니다 (즉,은 /some/dir/으로 비어 발견된다 find).


시험:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi

# 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
}

많은 파일이있는 디렉토리를 관리하십시오! ls명령 을 평가하는 데 시간이 걸릴 수 있습니다 .

IMO 최고의 솔루션은

find /some/dir/ -maxdepth 0 -empty

DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
     echo 'There is something alive in here'
fi

이것의 결과를 비교할 수 있습니까?

 ls -A /some/dir | wc -l

# 디렉토리에 숨겨지지 않은 파일이 있는지 확인합니다.
#
# 사용법 : if isempty "$ HOME"; then echo "Welcome home"; fi
#
비었다() {
    $ 1 / *의 _ief에 대해; 하다
        if [-e "$ _ief"]; 그때
            반환 1
        fi
    끝난
    반환 0
}

구현 참고 사항 :

  • for루프는 외부로 전화 방지 ls과정을. 여전히 모든 디렉토리 항목을 한 번 읽습니다. 이것은 readdir ()을 명시 적으로 사용하는 C 프로그램을 작성해야만 최적화 할 수 있습니다.
  • test -e루프 내부 변수가있는 경우 빈 디렉토리의 경우 잡는다 _ief값 "somedir / *"를 할당 할 것입니다. 해당 파일이 존재하는 경우에만 함수가 "비어 있지 않음"을 반환합니다.
  • 이 기능은 모든 POSIX 구현에서 작동합니다. 그러나 Solaris / bin / sh는 해당 범주에 속하지 않습니다. 그것의 test구현은 지원하지 않습니다 -e플래그.

이것은 정말 늦은 응답 일 수 있지만 여기에 작동하는 해결책이 있습니다. 이 줄은 파일의 존재 만 인식합니다! 디렉토리가 존재하는 경우 오 탐지를 제공하지 않습니다.

if find /path/to/check/* -maxdepth 0 -type f | read
  then echo "Files Exist"
fi

이것은 디렉토리가 비어 있는지 또는 비어 있지 않은 경우 포함 된 파일 수를 알려줍니다.

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

빈 디렉토리에 대한 모직 가이드 가 언급되지 않은 것에 놀랐습니다 . 이 가이드와 모든 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 : 실제로 그러한 테스트가 필요하지 않은 경우 그러한 파일이나 디렉토리가 없습니다.


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/bin3000 개 이상의 파일을 사용하는 경우 그다지 느리지 않음), 모든 디렉토리 / 파일 이름을 할당하기에 충분한 메모리를 사용합니다 (및 그 이상). 모두 인수로 함수에 전달 (해결)되므로 일부 쉘은 인수 수 및 / 또는 인수 길이에 제한이있을 수 있습니다.

디렉토리가 비어 있는지 확인하는 이식 가능한 빠른 O (1) 제로 리소스 방법이 있으면 좋을 것입니다.

최신 정보

위의 버전 is_emptyRich의 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 shfind -> dd에서 출력이 무작위로 잘린 파이프 의 버그 일 수 있습니다 ( 내가 사용한 cat경우 출력은 항상 동일 dd하며 인수가 있는 것 같습니다 count).


Bruno의 대답의 작은 변형 :

files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ] 
then
    echo "Contains files"
else
    echo "Empty"
fi

그것은 나를 위해 작동합니다


ZSH

나는 그 질문이 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)예를 들어 혼자서도 일반 파일을 나열합니다. 따라서 zshexpman 페이지 에 설명 된대로 (/)디렉토리 만 나열 하는 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), "실패, 전체 디렉토리에 대해 경고하지 마십시오"라고 읽을 수 있는 한정자가 필요합니다 .


olibre의 답변에서 힌트 (또는 여러 가지)를 취하면 Bash 기능이 좋습니다.

function isEmptyDir {
  [ -d $1 -a -n "$( find $1 -prune -empty 2>/dev/null )" ]
}

Because while it creates one subshell, it's as close to an O(1) solution as I can imagine and giving it a name makes it readable. I can then write

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

As for O(1) there are outlier cases: if a large directory has had all or all but the last entry deleted, "find" may have to read the whole thing to determine whether it's empty. I believe that expected performance is O(1) but worst-case is linear in the directory size. I have not measured this.


if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;

So far I haven't seen an answer that uses grep which I think would give a simpler answer (with not too many weird symbols!). Here is how I would check if any files exist in the directory using bourne shell:

this returns the number of files in a directory:

ls -l <directory> | egrep -c "^-"

you can fill in the directory path in where directory is written. The first half of the pipe ensures that the first character of output is "-" for each file. egrep then counts the number of line that start with that symbol using regular expressions. now all you have to do is store the number you obtain and compare it using backquotes like:

 #!/bin/sh 
 fileNum=`ls -l <directory> | egrep -c "^-"`  
 if [ $fileNum == x ] 
 then  
 #do what you want to do
 fi

x is a variable of your choice.


Mixing prune things and last answers, I got to

find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty"

that works for paths with spaces too


Simple answer with bash:

if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;

I would go for find:

if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
    echo "$dir has NO files"
else
    echo "$dir has files"

This checks the output of looking for just files in the directory, without going through the subdirectories. Then it checks the output using the -z option taken from man test:

   -z STRING
          the length of STRING is zero

See some outcomes:

$ mkdir aaa
$ dir="aaa"

Empty dir:

$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

Just dirs in it:

$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

A file in the directory:

$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile 

A file in a subdirectory:

$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty

Try with command find. Specify the directory hardcoded or as argument. Then initiate find to search all files inside the directory. Check if return of find is null. Echo the data of find

#!/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

With some workaround I could find a simple way to find out whether there are files in a directory. This can extend with more with grep commands to check specifically .xml or .txt files etc. Ex : ls /some/dir | grep xml | wc -l | grep -w "0"

#!/bin/bash
if ([ $(ls /some/dir | wc -l  | grep -w "0") ])
    then
        echo 'No files'
    else
        echo 'Found files'
fi

to test a specific target directory

if [ -d $target_dir ]; then
    ls_contents=$(ls -1 $target_dir | xargs); 
    if [ ! -z "$ls_contents" -a "$ls_contents" != "" ]; then
        echo "is not empty";
    else
        echo "is empty";
    fi;
else
    echo "directory does not exist";
fi;

I dislike the ls - A solutions posted. Most likely you wish to test if the directory is empty because you don't wish to delete it. The following does that. If however you just wish to log an empty file, surely deleting and recreating it is quicker then listing possibly infinite files?

This should work...

if !  rmdir ${target}
then
    echo "not empty"
else
    echo "empty"
    mkdir ${target}
fi

Works well for me this (when dir exist):

some_dir="/some/dir with whitespace & other characters/"
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

With full check:

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

참고URL : https://stackoverflow.com/questions/91368/checking-from-shell-script-if-a-directory-contains-files

반응형