Как узнать, существует ли обычный файл в Bash?

я использовал следующий скрипт, чтобы узнать, существует ли файл:

#!/bin/bash

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

какой правильный синтаксис использовать, если я хочу только проверить, делает ли файл не?

#!/bin/bash

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

17 ответов



Тестирование Файлов Bash

-b filename - специальный блочный файл
-c filename - специальный символьный файл
-d directoryname - проверьте наличие каталога
-e filename - проверка на существование файла, независимо от типа (узел, каталог, розетки и т. д.)
-f filename - проверьте наличие обычного файла, а не каталога
-G filename - проверьте, существует ли файл и принадлежит эффективной группе ID
-G filename set-group-id - True, если файл существует и set-group-id
-k filename - липкий бит
-L filename - символическая ссылка
-O filename - True, если файл существует и принадлежит эффективному id пользователя
-r filename - проверьте, является ли файл читаемым
-S filename - проверьте, является ли файл socket
-s filename - проверьте, если файл имеет ненулевой размер
-u filename - проверьте, установлен ли бит file 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 

A тест выражение можно отрицать с помощью ! оператор

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

вы можете отрицать выражение с помощью "!":

#!/bin/bash
FILE=

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

соответствующие man-страницы man test или, что эквивалентно, man [ -- или help test или help [ для встроенной команды bash.


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

стоит отметить, что если вам нужно выполнить одну команду можно сократить

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

to

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

или

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

Я предпочитаю делать следующий однострочный, в POSIX shell совместимый формат:

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

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

для нескольких команд, как я бы сделал в скрипте:

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

Как только я начал это делать,я редко использую полностью типизированный синтаксис!!


чтобы проверить существование файла, параметр может быть одним из следующих:

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

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

вы должны быть осторожны при запуске test для некотируемой переменной, поскольку это может привести к неожиданным результатам:

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

рекомендация обычно состоит в том, чтобы тестируемая переменная была окружена двойными кавычками:

#!/bin/sh
FILE=

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

существуют три различных способа сделать это:

  1. отрицание статуса выхода с bash (ни один другой ответ не сказал этого):

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

    или:

    ! [ -e "$file" ] && echo "file does not exist"
    
  2. отрицание теста внутри команды test [ (именно так большинство ответов до этого представили):

    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"
    

    это выглядит глупо (IMO), не используйте его, если ваш код не должен быть переносным в оболочку Bourne (например,/bin/sh Solaris 10 или более ранних версий), которому не хватало оператора отрицания трубопровода (!):

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

вы можете сделать это:

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

или

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

если вы хотите проверить файл и папку, а затем использовать вместо -f. -e возвращает true для обычных файлов, каталогов, сокетов, специальных файлов символов, специальных файлов блоков и т. д.


на

[ -f "$file" ]

the тут stat() (не lstat()) системный вызов по пути, хранящемуся в $file и возвращает правда если этот системный вызов выполняется успешно и тип файла, возвращаемого stat() - это "регулярные".

если [ -f "$file" ] возвращает true, вы можете сказать, файл существует и является обычным файлом или символической ссылкой, в конечном итоге, решать в обычный файл (или по крайней мере это было на момент stat()).

если он вернется false (или если [ ! -f "$file" ] или ! [ -f "$file" ] return true), есть много различных возможностей:
  • файл не существует
  • файл существует, но не является обычным файлом
  • файл существует, но у вас нет разрешения на поиск в Родительском каталоге
  • файл существует, но этот путь для доступа к нему слишком длинный
  • файл является символической ссылкой на обычный файл, но у вас нет разрешения на поиск для некоторых каталогов, участвующих в разрешении символической ссылки.
  • ... любая другая причина, почему 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 говорит нам, что один из компонентов пути не является каталогом, это еще один случай, когда мы можем сказать, что файл не существует по этому пути). К сожалению,[ команда не дает нам знать об этом. Он вернет false, является ли код ошибки ENOENT, EACCESS (разрешение отказано), ENAMETOOLONG или что-либо еще.

на [ -e "$file" ] тест также можно сделать с ls -Ld -- "$file" > /dev/null. В таком случае ...--20--> скажет вам, почему 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 говорит мне, что это не потому, что файл не существует, что он терпит неудачу. Потому что он не может сказать, существует файл или нет. The [ команда просто проигнорировала проблему.

С zsh shell, вы можете запросить код ошибки с помощью $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;;
    (*) echo "can't tell"; syserror "$err"
  esac
fi

(остерегайтесь $errnos поддерживает несколько версий zsh при построении с последними версиями gcc).


чтобы отменить тест, используйте "!". Это эквивалентно логическому оператору" не " на других языках. Попробуйте это:

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

который может быть записан (используя тогда "и" оператор:&&) как:

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

, который выглядит короче такой:

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

на test что может рассчитывать. Это сработало для меня (на основе Bash Shell: проверить файл существует или нет):

test -e FILENAME && echo "File exists" || echo "File doesn't exist"

этот код также работает .

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

самый простой способ

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

этот сценарий оболочки также работает для поиска файла в каталоге:

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

иногда может быть удобно использовать & & и / / операторы.

как в (если у вас есть команда "test"):

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

или

test -b $FILE || echo File there!