Bash에 일반 파일이 없는지 어떻게 알 수 있습니까?


3261

다음 스크립트를 사용하여 파일이 있는지 확인했습니다.

#!/bin/bash

FILE=$1     
if [ -f $FILE ]; then
   echo "File $FILE exists."
else
   echo "File $FILE does not exist."
fi

파일이 존재 하지 않는지 확인하고 싶을 때 올바른 구문은 무엇입니까 ?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi

187
bash 조건문 목록 이 매우 유용하다는 것을 알았습니다 .
Saulius Žemaitaitis

9
나는 매우 게으른 사람이기 때문에 일반적으로 다음과 같은 어리석은 해결 방법을 사용 if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi;했을 것입니다. :)
Alderath

5
대부분의 UNIX / POSIX 문서는 일반적으로 모든 유형의 파일 시스템 항목을 단순히 "파일"로 지칭하기 때문에 "정규 파일"이라고 말해야합니다. 예를 들어, 기호 링크는 명명 된 파이프와 같이 파일 유형 , 일반 파일, 디렉토리, 블록 스페셜, 문자 스페셜, 소켓 등
kevinarpe

11
@kevinarpe 무언가 존재 하는지 테스트 하려면을 사용하십시오 -e. -f는 디렉토리, 심볼릭 링크 등을 선택하지 않습니다.
Benubird

14
안전을 위해, 항상 큰 따옴표를 사용하여 공백이있는 파일 이름을 올바르게 처리하십시오 (예 : FILE=$1-> FILE="$1"if [ -f $FILE ];->if [ -f "$FILE" ];
kevinarpe

답변:


4521

테스트 명령 ( [여기) (다른 많은 언어와 유사) 느낌표입니다 "없습니다"논리 연산자가 있습니다. 이 시도:

if [ ! -f /tmp/foo.txt ]; then
    echo "File not found!"
fi

208
간결하게 : [! -f /tmp/foo.txt] && echo "파일을 찾을 수 없습니다!"
DavidWinterbottom

38
"2 개 파일 중 하나라도 존재하지 않는 경우"에 대한 올바른 구문을 찾기 위해 조금 어려움을 겪었습니다. 다음 두 작품 모두 :if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi
mivk

153
@DavidWinterbottom 더 즙이 많은 :[ -f /tmp/foo.txt ] || echo "File not found!"
David W.

27
매개 변수는 다음 중 하나 일 수 있습니다.-e: Returns true value, if file exists -f: Return true value, if file exists and regular file -r: Return true value, if file exists and is readable -w: Return true value, if file exists and is writable -x: Return true value, if file exists and is executable -d: Return true value, if exists and is a directory
SD.

5
! -fwith &&-f함께 사용하는 경우 비대칭 성이 있습니다 ||. 이것은 존재하지 않는 검사에 의해 리턴 된 종료 코드와 관련이 있습니다. 종료 코드 0으로 라인을 항상 깨끗하게 종료해야하는 경우 (이러한 제약 조건을 원하지 않는 경우) 두 방법을 서로 바꿔 사용할 수 없습니다. 또는 if명령문을 사용 하면 더 이상 존재하지 않는 검사의 종료 코드에 대해 걱정할 필요가 없습니다.
Acumenus 2

670

배쉬 파일 테스트

-b filename-특수 파일 차단
-c filename-특수 문자 파일
-d directoryname-디렉토리 존재
-e filename여부 확인-유형 (노드, 디렉토리, 소켓 등)에 관계없이
-f filename파일 존재 여부
-G filename확인- 디렉토리가 아닌 일반 파일 존재 여부 확인-파일이 존재하고 소유하고 있는지 확인 유효 그룹 ID-
-G filename set-group-id파일이 존재하고 set-group-id 이면 True-
-k filename고정 비트
-L filename-기호 링크
-O filename-파일이 존재하고 유효 사용자 ID가 소유하는
-r filename경우 True-파일을 읽을 수
-S filename있는지 확인-파일이 소켓
-s filename인지 확인- 파일이 소켓 인지 확인 파일 크기가 0이 아닌
-u filename경우-파일 set-user-id 비트가 설정되어
-w filename있는지 확인-파일이 쓰기
-x filename가능한지 확인-파일이 실행 가능한지 확인

사용하는 방법:

#!/bin/bash
file=./file
if [ -e "$file" ]; then
    echo "File exists"
else 
    echo "File does not exist"
fi 

테스트 발현 은 USING 의해 무효화 될 수 !연산자

#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 

1
@ 0x90 원하는 경우 내 게시물을 자유롭게 편집하여 목록에 추가 할 수 있습니다. 당신이 의미하는 것 같아요 : -n String-문자열의 길이가 0이 아닌지 확인하십시오. 아니면 file1 -nt file2-파일 1이 최신인지 확인하고 파일 2가 최신인지 확인하십시오 (이전에는 -ot를 사용할 수도 있습니다)
BlueCacti

1
-n 정보 : The unary operator -z tests for a null string, while -n or no operator at all returns True if a string is not empty.~ ibm.com/developerworks/library/l-bash-test/index.html
BlueCacti

1
왜 일부는 function 같은 함수를 추가하지 않았습니까 () {⏎ if [-e "$ 1"]; 그런 다음 echo "$ 1 존재"그렇지 않으면 echo "$ 1 존재하지 않음"fi}
Mz A

291

"!"로 표현식을 부정 할 수 있습니다.

#!/bin/bash
FILE=$1

if [ ! -f "$FILE" ]
then
    echo "File $FILE does not exist"
fi

관련 매뉴얼 페이지입니다 man test동등, 또는 man [- 또는 help test또는 help [를 위해 내장 된 bash는 명령.


4
에서 bash는 , [내장 명령입니다. 따라서 관련 정보는 오히려 help [...에 의해 얻어 지지만 이것은 내장 [의 동의어 임을 나타내 test므로 관련 정보는에 의해 얻어집니다 help test. 매뉴얼Bash Conditional Expression 섹션 도 참조하십시오 .
gniourf_gniourf 2016 년

@gniourf_gniourf : 네,하지만 bash는 내장 [외부에 매우 유사 명령 동작합니다 [때문에 중, 명령 man test또는 man [당신에게 그것이 작동하는 방법의 좋은 아이디어를 줄 것이다.
Keith Thompson

8
@KeithThompson bash 내장 [[시스템에서 발견 되는 외부 명령보다 더 많은 스위치를 가지고 있다는 것을 제외하고 ... 일반적으로 말하면, 모호하게 관련된 다른 도구가 아닌 특정 도구에 대한 문서를 읽는 것이 낫다고 생각합니다. 나는 비록 잘못 될 수도;)
gniourf_gniourf

134
[[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE"

또한 파일이 깨진 심볼릭 링크이거나 비정규 파일 (예 : 소켓, 장치 또는 fifo) 일 수 있습니다. 예를 들어 깨진 심볼릭 링크를 확인하려면 다음을 수행하십시오.

if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!\n' "$FILE"
    else
        printf '%s does not exist!\n' "$FILE"
    fi
fi

9
테스트에서 두 "["가 왜 나타나는지 물어봐도 될까요? (예 : [[! -a $ FILE]]). 나는 solaris 상자에 언급 된 모든 옵션을 시도했지만 그 중 하나만 그렇게 감사했지만 왜 그랬습니까?
Dimitrios Mistriotis

30
이중 괄호는 "현대"확장입니다. 예를 들어, 단어 분리 (예 : 공백이있는 파일 이름)는하지 않고 빈 문자열에도 작동합니다. mywiki.wooledge.org/BashFAQ/031
bw1024

7
tldp.org/LDP/abs/html/fto.html 에 따르면 -a는 -e와 사실상 동일합니다. "더 이상 사용되지 않으며"사용하지 않는 것이 좋습니다. 어쨌든 +1 너무 깨진 심볼릭 링크를 확인하는 언급을위한
루카 Borrione을

4
@dimitrismistriotis 두 개의 "["는 zsh & bash에 의해 구현 된 이식 불가능한 확장이다; 일반적으로 가능하다면 피해야합니다.
Good Person

7
나는 그것이 [[. 널리 사용되는 확장입니다. bash를 사용하고 있다는 것을 알고 있다면 사용하지 않을 이유가 없습니다. [.보다 오류가 발생하기 쉽습니다.
Michael Potter

101

단일 명령을 실행해야하는 경우 약어를 사용할 수 있습니다.

if [ ! -f "$file" ]; then
    echo "$file"
fi

test -f "$file" || echo "$file"

또는

[ -f "$file" ] || echo "$file"

감사! [[]]를 사용하지 않는 대안이 필요함
Jonathan

69

POSIX 셸 호환 형식으로 다음과 같은 단일 라이너를 선호 합니다.

$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"

$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"

스크립트에서와 같이 몇 가지 명령의 경우 :

$  [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}

일단이 작업을 시작하면 더 이상 완전 형식의 구문을 거의 사용하지 않습니다!


1
우선, 인용되지 않은 변수 참조는 오류가 발생하기 쉽습니다. 즉, bash 맨 페이지 에서 내장 또는 내장 이 기본적으로 인수의 파일 존재 여부 를 테스트 한다고 말하는 것은 무엇 입니까? 모호하지 않습니까? AFAIK (와 AIUI 절 "조건식") 당신의 접근 방식으로 테스트되는 유일한 인수가이 경우에, 동어 반복이 (하자,이다 빈 (또는 정의)되지 않는 것입니다 및 다음 인수는 여전히, ). [test-e$DIR = ''$FILE = '''//'
PointedEars

1
증명 : ls /foo, 결과 ls: cannot access /foo: No such file or directory. [ /foo ] && echo 42결과 42. GNU bash, 버전 4.2.37 (1)-릴리스 (i486-pc-linux-gnu).
PointedEars

@ PointedEars : -f이 답변을 쓰는 ​​순간 옵션 을 지정하지 못했습니다 . -e확실하지 않은 경우 항상 파일을 사용할 수 있습니다. 또한 모든 스크립트 에서이 구문을 인용하면 적절한 교정없이이를 제출해야합니다.
JM Becker

ACK. 그러나 원 라이너가 if-else 문제를 해결할 수 없다는 것을 알고있을 것입니다 : [ $condition ] && if_true || if_false오류가 발생하기 쉽습니다. 어쨌든 나는 [ ! -f "$file" ] && if_not_exists보다 읽기 쉽고 이해하기 쉽다 [ -f "$file" ] || if_not_exists.
PointedEars

55

파일 존재를 테스트하기 위해 매개 변수는 다음 중 하나 일 수 있습니다.

-e: Returns true if file exists (regular file, directory, or symlink)
-f: Returns true if file exists and is a regular file
-d: Returns true if file exists and is a directory
-h: Returns true if file exists and is a symlink

아래의 모든 테스트는 일반 파일, 디렉토리 및 심볼릭 링크에 적용됩니다.

-r: Returns true if file exists and is readable
-w: Returns true if file exists and is writable
-x: Returns true if file exists and is executable
-s: Returns true if file exists and has a size > 0

스크립트 예 :

#!/bin/bash
FILE=$1

if [ -f "$FILE" ]; then
   echo "File $FILE exists"
else
   echo "File $FILE does not exist"
fi

39

당신은 이것을 할 수 있습니다 :

[[ ! -f "$FILE" ]] && echo "File doesn't exist"

또는

if [[ ! -f "$FILE" ]]; then
    echo "File doesn't exist"
fi

파일과 폴더를 모두 확인하려면 -e대신 옵션 을 사용하십시오 -f. -e일반 파일, 디렉토리, 소켓, 문자 특수 파일, 블록 특수 파일 등에 대해 true를 반환합니다.


1
그것은 배쉬 특정이 아닙니다. 구문은 Korn 쉘에서 제공되며 zsh 및 bash에서도 사용 가능합니다. 그러나 표준 [유틸리티 보다 이점이 제한적 입니다.
Stephane Chazelas

일반 파일 (확인한 파일 -f)과 디렉토리 는 여러 유형의 파일 중 두 개일뿐 입니다. 소켓, symlinks, 장치, fifos, doors도 있습니다 ... symlink 확인 후[ -e 파일의 존재 여부 (정규, fifo, 디렉토리 포함)를 테스트합니다 .
Stephane Chazelas

@StephaneChazelas : ksh 또는 zsh 태그가 어디에도 없습니다. 우리는 bash 또는 대부분의 유닉스 시스템에서 표준화 된 것에 대해 이야기하고 있습니다. 따라서 컨텍스트 내에서 배쉬마다 다릅니다. OP는 모든 포탄을 알 필요가 없습니다 : D
Jahid

그것은 답변 의 "Bash specific" 부분 에 대한 의견이었습니다 .
Stephane Chazelas

@StephaneChazelas : 예. 컨텍스트 내에서 (bash 및 표준 sh) bash마다 다릅니다. 나는 두 번째 의견에서 요점을 보지 못합니다. 그것은 문맥에서 완전히 벗어났습니다. 영업 이익은 필요하지 않습니다 -e그는 필요 -f.
Jahid

35

test따옴표없는 변수를 실행 하면 예기치 않은 결과가 발생할 수 있으므로주의해야합니다 .

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1

권장 사항은 일반적으로 테스트 변수를 큰 따옴표로 묶는 것입니다.

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi

8
불필요하게 드문 경우 나 유해한 드문 경우 중 하나를 정확히 알고 있지 않는 한 모든 변수를 큰 따옴표로 묶는 것이 좋습니다 . (아니,이 중 하나가 아닙니다.)
Uwe

큰 따옴표를 사용하지 않는 이유를 자세히 설명 하시겠습니까? 그렇지 않으면 의견에 유용성이 없습니다.
artdanil

4
나는 의미 : 이것은 불필요하거나 유해한 드문 경우 중 하나가 아닙니다. 쉘 프로그래머는 (거의) 모든 변수를 큰 따옴표로 묶어야합니다. 이 규칙은로 제한되지 않습니다 [ ... ].
Uwe


24

이를 수행하는 세 가지 방법이 있습니다.

  1. bash로 종료 상태를 무효화하십시오 (다른 대답은 이것을 말하지 않았습니다).

    if ! [ -e "$file" ]; then
        echo "file does not exist"
    fi

    또는:

    ! [ -e "$file" ] && echo "file does not exist"
  2. 테스트 명령 내부에서 테스트를 무효화하십시오 [(즉, 대부분의 답변이 제시된 방식 임).

    if [ ! -e "$file" ]; then
        echo "file does not exist"
    fi

    또는:

    [ ! -e "$file" ] && echo "file does not exist"
  3. 테스트 결과가 부정적 일 경우에 행동하십시오 ( ||대신 &&) :

    뿐:

    [ -e "$file" ] || echo "file does not exist"

    /bin/sh파이프 라인 부정 연산자 ( !) 가없는 Bourne 쉘 ( Solaris 10 이하 와 같은)에 코드를 이식 할 수 없다면, 어리석은 것처럼 보입니다 (IMO ).

    if [ -e "$file" ]; then
        :
    else
        echo "file does not exist"
    fi

! [과 (와) [ !? 사이의 이식성 차이
Frozen Flame

3
! [ 쉘 파이프 라인 2.9.2 (모든 명령)에 대한 POSIX입니다 Otherwise, the exit status shall be the logical NOT of the exit status of the last command[ ! 시험 POSIX입니다 ! expression True if expression is false. False if expression is true. 모두 POSIX, 그리고 내 경험, 모두 광범위하게 지원됩니다, 그래서.

1
@FrozenFlame, Bourne 쉘 !에는 Korn 쉘이 도입 한 키워드가 없었습니다. Solaris 10 이상을 제외하고는 요즘 Bourne 쉘을 발견하지 못할 것입니다.
Stephane Chazelas

22

[ -f "$file" ]

[명령은 저장된 경로에서 stat()(아님 lstat()) 시스템 호출을 수행하고 해당 시스템 호출이 성공하고 파일 형식 이 " regular " 경우 true를$file 리턴 합니다 .stat()

따라서 [ -f "$file" ]true를 반환하면 파일이 존재하고 일반 파일 또는 결국 일반 파일로 해석되는 심볼릭 링크라고 말할 수 있습니다 stat().

그러나 false를 반환 [ ! -f "$file" ]하거나 ! [ -f "$file" ]true 또는 true를 반환 하면 여러 가지 가능성이 있습니다.

  • 파일이 존재하지 않습니다
  • 파일이 존재하지만 일반 파일 이 아닙니다 (장치, fifo, 디렉토리, 소켓 등일 수 있음).
  • 파일이 존재하지만 상위 디렉토리에 대한 검색 권한이 없습니다
  • 파일이 존재하지만 액세스 할 수있는 경로가 너무 깁니다
  • 파일은 일반 파일에 대한 심볼릭 링크이지만 심볼릭 링크를 해결하는 데 관련된 일부 디렉토리에 대한 검색 권한이 없습니다.
  • ... stat()시스템 호출이 실패 할 수 있는 다른 이유 .

간단히 말해 다음과 같아야합니다.

if [ -f "$file" ]; then
  printf '"%s" is a path to a regular file or symlink to regular file\n' "$file"
elif [ -e "$file" ]; then
  printf '"%s" exists but is not a regular file\n' "$file"
elif [ -L "$file" ]; then
  printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file"
else
  printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file"
fi

파일이 존재하지 않음을 확인하려면 stat()오류 코드와 함께 리턴 하는 시스템 호출이 필요합니다 ENOENT( ENOTDIR경로 구성 요소 중 하나가 디렉토리가 아닌 경로임을 알려줍니다. 해당 경로로 존재합니다). 불행히도 [명령은 우리에게 그것을 알려주지 않습니다. 오류 코드가 ENOENT, EACCESS (권한이 거부 됨), ENAMETOOLONG 또는 다른 어떤 것이 든 거짓을 리턴합니다.

[ -e "$file" ]테스트도 수행 할 수 있습니다 ls -Ld -- "$file" > /dev/null. 이 경우 정보를 프로그래밍 방식으로 쉽게 사용할 수 없지만 실패한 ls이유를 알려줍니다 stat().

$ file=/var/spool/cron/crontabs/root
$ if [ ! -e "$file" ]; then echo does not exist; fi
does not exist
$ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi
ls: cannot access '/var/spool/cron/crontabs/root': Permission denied
stat failed

적어도 ls파일이 존재하지 않기 때문에 파일이 존재하지 않기 때문에 그렇지 않다고 말합니다. 파일의 존재 여부를 알 수 없기 때문입니다. [명령은 문제를 무시했다.

zsh셸을 사용하면 $ERRNO실패한 [명령 다음에 특수 변수를 사용하여 오류 코드를 쿼리 $errnos하고 zsh/system모듈 의 특수 배열을 사용하여 해당 번호를 디코딩 할 수 있습니다 .

zmodload zsh/system
ERRNO=0
if [ ! -f "$file" ]; then
  err=$ERRNO
  case $errnos[err] in
    ("") echo exists, not a regular file;;
    (ENOENT|ENOTDIR)
       if [ -L "$file" ]; then
         echo broken link
       else
         echo does not exist
       fi;;
    (*) syserror -p "can't tell: " "$err"
  esac
fi

(의 최신 버전으로 빌드 할 때 $errnos일부 버전zshgcc 에서는 지원이 중단되었습니다 ).


11

테스트를 취소하려면 "!"를 사용하십시오. 다른 언어의 "not"논리 연산자와 같습니다. 이 시도:

if [ ! -f /tmp/foo.txt ];
then
    echo "File not found!"
fi

또는 약간 다른 방식으로 작성되었습니다.

if [ ! -f /tmp/foo.txt ]
    then echo "File not found!"
fi

또는 다음을 사용할 수 있습니다.

if ! [ -f /tmp/foo.txt ]
    then echo "File not found!"
fi

또는 모두 함께 모아서 :

if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi

다음과 같이 쓸 수 있습니다 ( "and"연산자를 사용하여 &&) :

[ ! -f /tmp/foo.txt ] && echo "File not found!"

다음과 같이 더 짧게 보입니다.

[ -f /tmp/foo.txt ] || echo "File not found!"


10

이 코드도 작동합니다.

#!/bin/bash
FILE=$1
if [ -f $FILE ]; then
 echo "File '$FILE' Exists"
else
 echo "The File '$FILE' Does Not Exist"
fi

7

가장 간단한 방법

FILE=$1
[ ! -e "${FILE}" ] && echo "does not exist" || echo "exists"

6

이 쉘 스크립트는 디렉토리에서 파일을 찾는 데에도 사용됩니다.

echo "enter file"

read -r a

if [ -s /home/trainee02/"$a" ]
then
    echo "yes. file is there."
else
    echo "sorry. file is not there."
fi

3
이것이 다른 답변이 아직 제공하지 않은 것을 추가한다는 것은 확실하지 않습니다. 경로 이름을 하드 코딩합니다. 문제는 태그이기 때문에 배쉬는 , 그것은 사용할 수 있습니다 read -p "Enter file name: " -r a뿐만 아니라 읽을 때 프롬프트. 변수 주위에 따옴표를 사용합니다. 그것은 좋지만 설명해야합니다. 파일 이름을 에코하면 더 나을 수 있습니다. 그리고 이것은 파일이 존재하고 비어 있지 않은지 (즉,의 의미 임 -s) 확인하지만 비어 있거나 아닌 ( -f더 적합한) 파일에 대해 질문합니다 .
Jonathan Leffler

4

때로는 && 및 ||를 사용하는 것이 편리 할 수 ​​있습니다. 연산자.

"test"명령이있는 경우와 같이 :

test -b $FILE && echo File not there!

또는

test -b $FILE || echo File there!

2

사용하고자하는 경우 test대신 [], 당신은 사용할 수있는 !부정을 얻을 :

if ! test "$FILE"; then
  echo "does not exist"
fi

0

하나의 라이너에 여러 명령을 그룹화 할 수도 있습니다

[ -f "filename" ] || ( echo test1 && echo test2 && echo test3 )

또는

[ -f "filename" ] || { echo test1 && echo test2 && echo test3 ;}

filename이 종료되지 않으면 출력은

test1
test2
test3

참고 : (...)는 서브 쉘에서 실행되며 {...;}는 동일한 쉘에서 실행됩니다. 중괄호 표기법은 bash에서만 작동합니다.


1
아니, 중괄호 표기법은 하지 bash는 전용 POSIX 호환 쉘에서 작동합니다.
찰스 더피

0
envfile=.env

if [ ! -f "$envfile" ]
then
    echo "$envfile does not exist"
    exit 1
fi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.