it-swarm.com.ru

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

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

#!/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
2942
Bill the Lizard

Команда test (здесь [) имеет логический оператор "not", который является восклицательным знаком (аналогично многим другим языкам). Попробуй это:

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

Bash File Testing

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

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

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

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

#!/bin/bash
FILE=$1

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

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

274
unbeknown
[[ -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
126
guns

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

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

в

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

или же

[ -f "$file" ] || echo "$file"
91
Elazar Leibovich

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

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

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

Для пары команд, как я сделал бы в сценарии:

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

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

64
J. M. Becker

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

-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
48
SD.

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

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

или же

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

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

33
Jahid

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

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

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

#!/bin/sh
FILE=$1

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

Есть три различных способа сделать это:

  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 Shell (например, /bin/sh в Solaris 10 или более ранней версии), в котором отсутствует оператор отрицания конвейера (!):

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

В

[ -f "$file" ]

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

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

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

19
Stephane Chazelas

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

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!"
10
user2350426

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

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

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

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

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

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

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

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
5
Simmant

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

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

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

или же

test -b $FILE || echo File there!
3
André

Вы также можете сгруппировать несколько команд в один вкладыш

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

или же

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

Если имя файла не выходит, вывод будет

test1
test2
test3

Примечание: (...) работает в подоболочке, {...;} работает в той же оболочке. Запись в фигурных скобках работает только в bash.

0
upteryx