Как мне узнать, что обычный файл не существует в 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
17 ответов
Тестовая команда ([
здесь) имеет "не" логический оператор, который является восклицательным знаком (аналогично многим другим языкам). Попробуй это:
if [ ! -f /tmp/foo.txt ]; then
echo "File not found!"
fi
Тестирование файлов Bash
-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
- True, если файл существует и принадлежит эффективному идентификатору пользователя-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
Вы можете отрицать выражение с "!":
#!/bin/bash
FILE=$1
if [ ! -f "$FILE" ]
then
echo "File $FILE does not exist"
fi
Соответствующая страница руководства 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
в
test -f "$file" || echo "$file"
или же
[ -f "$file" ] || echo "$file"
Я предпочитаю делать следующий однострочник в формате, совместимом с POSIX:
$ [ -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=$1
if [ -f "$FILE" ]; then
echo "File $FILE exists"
else
echo "File $FILE does not exist"
fi
Вы можете сделать это:
[[ ! -f "$FILE" ]] && echo "File doesn't exist"
или же
if [[ ! -f "$FILE" ]]; then
echo "File doesn't exist"
fi
Если вы хотите проверить оба файла и папки, используйте -e
вариант вместо -f
, -e
возвращает true для обычных файлов, каталогов, сокетов, специальных файлов символов, блокировки специальных файлов и т. д.
Вы должны быть осторожны с бегом test
для переменной без кавычек, потому что это может привести к неожиданным результатам:
$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1
Обычно рекомендуется, чтобы проверяемая переменная была заключена в двойные кавычки:
#!/bin/sh
FILE=$1
if [ ! -f "$FILE" ]
then
echo "File $FILE does not exist."
fi
В
[ -f "$file" ]
[
команда делает stat()
(не lstat()
) системный вызов по пути, хранящемуся в $file
и возвращает true, если этот системный вызов завершился успешно, а тип файла возвращается stat()
является "регулярным".
Так что если [ -f "$file" ]
возвращает true, вы можете сказать, что файл существует и является обычным файлом или символической ссылкой, в конечном итоге преобразующейся в обычный файл (или, по крайней мере, это было во время stat()
).
Однако, если он возвращает ложь (или если [ ! -f "$file" ]
или же ! [ -f "$file" ]
верните 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
, В таком случае, 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;;
(*) echo "can't tell"; syserror "$err"
esac
fi
(остерегайтесь $errnos
поддержка сломана с некоторыми версиями zsh
когда построен с последними версиями gcc
).
Есть три различных способа сделать это:
Отмените статус выхода с помощью bash (другой ответ не сказал этого):
if ! [ -e "$file" ]; then echo "file does not exist" fi
Или же:
! [ -e "$file" ] && echo "file does not exist"
Отменить тест внутри команды теста
[
(именно так большинство ответов раньше представляли):if [ ! -e "$file" ]; then echo "file does not exist" fi
Или же:
[ ! -e "$file" ] && echo "file does not exist"
Действовать на результат теста отрицательным (
||
вместо&&
):Только:
[ -e "$file" ] || echo "file does not exist"
Это выглядит глупо (IMO), не используйте его, если ваш код не должен переноситься на оболочку Bourne (например,
/bin/sh
Solaris 10 или более ранней версии), в которой отсутствовал оператор отрицания конвейера (!
):if [ -e "$file" ]; then : else echo "file does not exist" fi
envfile=.env
if [ ! -f "$envfile" ]
then
echo "$envfile does not exist"
exit 1
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
Или, давя все вместе:
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!"
Этот код также работает.
#!/bin/bash
FILE=$1
if [ -f $FILE ]; then
echo "File '$FILE' Exists"
else
echo "The File '$FILE' Does Not Exist"
fi
test
вещь тоже может рассчитывать. Это сработало для меня (на основе Bash Shell: Проверить наличие файла или нет):
test -e FILENAME && echo "File exists" || echo "File doesn't exist"
Самый простой способ
FILE=$1
[ ! -e "${FILE}" ] && echo "does not exist" || echo "exists"
Иногда может быть удобно использовать && и || операторы.
Как в (если у вас есть команда "тест"):
test -b $FILE && echo File not there!
или же
test -b $FILE || echo File there!
Этот сценарий оболочки также работает для поиска файла в каталоге:
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
вместо того []
, тогда вы можете использовать !
чтобы получить отрицание:
if ! test "$FILE"; then
echo "does not exist"
fi
Вы также можете сгруппировать несколько команд в одном лайнере
[ -f "filename" ] || ( echo test1 && echo test2 && echo test3 )
или
[ -f "filename" ] || { echo test1 && echo test2 && echo test3 ;}
Если имя файла не завершается, вывод будет
test1
test2
test3
Примечание: ( ...) выполняется в подоболочке, { ...;} выполняется в той же оболочке. Обозначение фигурных скобок работает только в bash.