Bash, как проверить, существует ли файл

Обновлено: 21.11.2024

В этой статье мы напишем bash-скрипт для проверки существования файлов.

Синтаксис:

  • проверить [выражение]
  • [выражение]
  • [[ выражение ]]
  • –f: возвращает True, если файл существует как обычный (обычный) файл.
  • -d: возвращает True, если каталог существует.
  • -e: возвращает True, если существует файл любого типа.
  • -c: возвращает True, если файл символов существует.
  • -r: возвращает True, если файл для чтения существует.
  • –w: возвращает True, если существует файл, доступный для записи.
  • -x: возвращает True, если исполняемый файл существует.
  • -p: возвращает True, если файл существует в виде канала.
  • -S: возвращает True, если файл существует как сокет.
  • -s: возвращает True, если файл существует и размер файла не равен нулю.
  • -L: возвращает True, если файл символической ссылки существует.
  • -g: возвращает True, если файл существует и установлен флаг удержания группы.
  • -G: яt возвращает True, если файл существует и содержит тот же идентификатор группы, что и в процессе.
  • -k: возвращает True, если файл существует и установлен флаг закрепления битов.
  • -ef: возвращает True, если оба файла существуют и указывают на один и тот же файл.
  • -nt: возвращает True, если FirstFile новее, чем Secondfile.

Пример:

  • -ot: возвращает True, если FirstFile старше, чем SecondFile.

Пример:

Давайте рассмотрим несколько примеров на основе синтаксиса:

  • [ выражение ]: сначала создайте файл с именем «FirstFile.sh» и напишите в нем следующий скрипт

Теперь сохраните и запустите файл, используя следующую команду

Вывод:

  • test [выражение]: теперь измените приведенный выше скрипт в «FirstFile.sh» следующим образом

Теперь снова сохраните и запустите файл, используя следующую команду

Вывод:

  • [[выражение]]: снова измените приведенный выше скрипт в «FirstFile.sh» следующим образом

Теперь снова сохраните и запустите файл, используя следующую команду

Вывод:

Примечание. Поскольку в системе присутствует файл «File3.txt». Итак, он напечатал «Файл существует».

Давайте рассмотрим пример на основе параметров:

  • Используя параметр -d: создайте файл с именем «FirstDir.sh» и напишите в нем следующий скрипт

Теперь сохраните и запустите файл, используя следующую команду

Вывод:

Примечание. Поскольку в системе присутствует «GFG_dir». Итак, он напечатал «Каталог существует».

Точно так же вы можете использовать -f , -e , -w , -r , -c и т. д. (в соответствии с их использованием) вместо -d для проверки существования различных типов файлов.

Когда вы работаете над сценарием оболочки в bash, бывают случаи, когда вы хотите проверить, существует ли конкретный файл (или не существует) в каталоге, а затем выполнить действие на основе условия. В bash есть несколько способов проверить, существует ли файл в bash. Далее я продемонстрирую несколько примеров сценариев оболочки bash для этого варианта использования.

Проверить, существует ли файл в bash

Самый простой способ проверить, существует ли файл, — использовать команду test. С опцией -f команда test возвращает true, если указанный файл существует.

В качестве альтернативы вы можете использовать встроенный флаг bash -f , который может проверять наличие файла при использовании внутри условных выражений bash.

Также можно использовать следующую сокращенную однострочную запись, в которой условная проверка и соответствующее действие записываются в одну строку.

Проверить, не существует ли файл в bash

Если вы хотите проверить, что файл не существует в bash , вы можете просто добавить ! в приведенных выше условных выражениях.

Проверить, существует ли какой-либо файл с расширением в bash

Во всех предыдущих примерах сценария bash имя проверяемого файла заранее определено и известно. Что делать, если вы хотите проверить, существует ли какой-либо файл с шаблоном (например, с определенным расширением)? В этом случае имя файла(ов) для проверки неизвестно. Обратите внимание, что команда test и флаг bash -f не работают с подстановочными знаками.

Самый простой способ проверить, существует ли файл с подстановочным знаком, — использовать команду ls. Вы просто проверяете, возвращает ли ls (с шаблоном) ненулевое значение.

Еще один способ — использовать команду compgen. Вы можете использовать параметр -G, чтобы указать шаблон глобуса. Подобно ls, compgen возвращает список совпадающих файлов.

Также возможны следующие сокращенные однострочники.

Если вы найдете это руководство полезным, я рекомендую вам ознакомиться с серией руководств по написанию сценариев оболочки bash, предоставленных Xmodulo.

Поддержка Xmodulo

Этот веб-сайт стал возможен благодаря минимальной рекламе и вашему любезному пожертвованию через PayPal (кредитная карта) или биткойн ( 1M161JGAkz3oaHNvTiPFjNYkeABox8rb4g ).

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

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

Будучи очень ленивым человеком, я обычно использовал следующую глупую обходную конструкцию: if [ -f $FILE ]; тогда; еще; echo "Файл $FILE не существует."; фи; Наверное, хорошо, что вместо этого я нашел этот вопрос и научился делать это более правильно. :)

Чтобы быть подвесным, вы должны сказать "обычный файл", так как большинство документов UNIX/POSIX ссылаются в общем на все типы записей файловой системы, а просто "файлы", например, символическая ссылка - это тип файла, как именованный канал, обычный файл, каталог, специальный блок, специальный символ, сокет и т. д.

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

В целях безопасности всегда используйте двойные кавычки для правильной обработки имен файлов с пробелами, например, FILE=$1 -> FILE="$1" и if [ -f $FILE ]; -> если [ -f "$ФАЙЛ" ];

20 ответов 20

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

Я немного потрудился, чтобы найти правильный синтаксис для "если какой-либо из двух файлов не существует". Оба варианта работают: если [ ! \(-f "f1" -a -f "f2" \) ] ; затем эхо ОТСУТСТВУЕТ; фи если [ ! -f "f1" ] || [ ! -f "f2" ] ; затем эхо ОТСУТСТВУЕТ; фи

Параметр может быть любым из следующих: -e: возвращает истинное значение, если файл существует -f: возвращает истинное значение, если файл существует и является обычным файлом -r: возвращает истинное значение, если файл существует и доступен для чтения -w : Вернуть истинное значение, если файл существует и доступен для записи -x: Вернуть истинное значение, если файл существует и является исполняемым -d: Вернуть истинное значение, если существует и является каталогом

Существует асимметрия в использовании ! -f с && против использования -f с || . Это связано с кодом выхода, возвращаемым проверкой отсутствия/существования. Если вам нужно, чтобы ваша линия всегда завершалась корректно с кодом выхода 0 (и иногда вам не нужно это ограничение), эти два подхода не взаимозаменяемы. В качестве альтернативы просто используйте оператор if, и вам больше не придется беспокоиться о коде выхода вашей проверки отсутствия/существования.

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

-b имя_файла — заблокировать специальный файл
-c имя_файла — файл со специальными символами
-d имя_каталога — проверить наличие каталога
-e имя_файла — проверить наличие файла, независимо от его типа ( узел, каталог, сокет и т. д.)
-f имя_файла — Проверить наличие обычного файла, а не каталога
-G имя_файла — Проверить, существует ли файл и принадлежит ли он эффективному идентификатору группы
-G имя_файла set-group-id — Истинно, если файл существует и имеет set-group-id
-k имя_файла — Sticky bit
-L имя_файла — символическая ссылка
-O имя_файла — True, если файл существует и принадлежит действующему идентификатору пользователя
-r имя_файла — проверить, является ли файл доступным для чтения
-S имя_файла — проверить, является ли файл сокетом
-s имя_файла — проверить, имеет ли файл ненулевой размер < br />-u имя_файла — проверить, установлен ли в файле бит set-user-id
-w имя_файла — проверить, доступен ли файл для записи
-x имя_файла — проверить, является ли файл исполняемым

Как использовать:

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

@0x90 Если хотите, можете отредактировать мой пост и добавить его в список. Я думаю, вы имеете в виду: -n String — Проверить, не равна ли длина строки нулю. Или вы имеете в виду файл1 -nt файл2 - проверьте, является ли файл 1 более новым, чем файл 2 (вы также можете использовать -ot для более старого)

@MzA, потому что нам нужно сделать код читаемым, никто не знает, что такое $1. Поэтому назначьте $1 как файл, а затем используйте эту файловую переменную, чтобы сделать что-то еще, что выглядит более читабельно, чем использование неизвестного аргумента $1

Что касается оператора -G, то, насколько я понимаю, они немного отличаются. в разделе «SETUID & SETGID BITS» справочной страницы chmod эти два значения будут давать разные значения в случае пользователя root, не так ли? Я имею в виду именно часть «если у пользователя нет соответствующих разрешений». Несмотря ни на что, отличный ответ. Закладки только для этого.

Вы можете отменить выражение внутри теста (для которого [ является псевдонимом) с помощью "!":

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

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

Этот синтаксис описан в "man 1 bash" в разделах "Конвейеры" и "Составные команды".

В bash [ является встроенной функцией. Таким образом, соответствующая информация скорее получена с помощью [ . но это показывает, что [ является синонимом встроенного теста, поэтому соответствующая информация скорее получается с помощью справочного теста. См. также раздел «Условное выражение Bash» в руководстве.

@gniourf_gniourf: Да, но встроенная в bash команда [ ведет себя очень похоже на внешнюю команду [, поэтому либо man test, либо man [ дадут вам хорошее представление о том, как это работает.

@KeithThompson, за исключением того, что встроенная команда bash [ имеет больше переключателей, чем внешняя команда [ найденная в моей системе. Вообще говоря, я считаю, что лучше читать документацию, относящуюся к данному инструменту, а не документацию, относящуюся к другому смутно связанному инструменту. Хотя могу ошибаться ;)

Кроме того, файл может быть неработающей символической ссылкой или нестандартным файлом, например, сокет, устройство или FIFO. Например, чтобы добавить проверку на битые симлинки:

Могу ли я спросить, почему два "[" в тесте? (например, [[ ! -a $FILE ]]). Я перепробовал все варианты, упомянутые на коробке Solaris, и только этот сработал, очень благодарен, но почему?

согласно tldp.org/LDP/abs/html/fto.html -a фактически идентично -e. Он был «устарел», и его использование не рекомендуется. В любом случае +1 за упоминание о проверке неработающих символических ссылок

@dimitrismistriotis two "[" — это непереносимое расширение, реализованное (по-разному) в zsh & bash; как правило, вам следует избегать этого, если это вообще возможно.

См. SO 321348, чтобы узнать, почему -a нельзя инвертировать в условных выражениях с одной скобкой. Я предлагаю вообще избегать -a.

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

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

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

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

Прежде всего, ссылки на переменные без кавычек подвержены ошибкам. Тем не менее, где на любой справочной странице bash сказано, что встроенный [ or test будет проверять существование файла аргумента по умолчанию (в отличие от -e ) ? Не будет ли это двусмысленностью? Насколько я знаю (и AIUI раздел «УСЛОВНЫЕ ВЫРАЖЕНИЯ»), единственное, что проверяется с вашим подходом, это то, что аргумент не пуст (или не определен), что в данном случае является тавтологией (пусть $DIR = '' и $ FILE = '' , то аргумент по-прежнему '//' ).

Доказательство: ls /foo , результат ls: невозможно получить доступ к /foo: нет такого файла или каталога . [ /foo ] && echo 42 , результат 42 . GNU bash, версия 4.2.37(1)-выпуск (i486-pc-linux-gnu).

@PointedEars: мне не удалось указать параметр -f, когда я писал этот ответ. Очевидно, вы всегда можете использовать -e , если не уверены, что это будет обычный файл. Кроме того, во всех своих сценариях я цитирую эти конструкции, должно быть, я только что отправил их без надлежащей проверки.

Подтверждение. Но вы, вероятно, знаете, что однострочник не может решить проблему if-else: [ $condition ] && if_true || if_false подвержен ошибкам. В любом случае, я нахожу [ ! -f "$file" ] && if_not_exists легче читать и понимать, чем [ -f "$file" ] || если_не_существует .

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

Все приведенные ниже тесты применимы к обычным файлам, каталогам и символическим ссылкам:

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

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

Это не зависит от bash. Синтаксис взят из оболочки Korn, а также доступен в zsh и bash. Однако у него есть ограниченное преимущество перед стандартной утилитой [ здесь.

обычные файлы (проверяемые с помощью -f ) и каталоги — это всего лишь два из многих различных типов файлов. Также есть сокеты, симлинки, устройства, фифы, двери. [ -e проверит наличие файла (любого типа, включая обычный, fifo, каталог. ) после разрешения символической ссылки.

@StephaneChazelas: я нигде не вижу тегов ksh или zsh. Мы говорим о bash или о чем-то, что стандартизировано для большинства unix-систем. Итак, в контексте это специфично для bash. ОП не нужно знать обо всех существующих оболочках: D

@StephaneChazelas: Да, и в контексте (bash и стандартный sh) это специфично для bash. Не вижу смысла во втором вашем комментарии, он совершенно не в тему. OP не нужен -e , ему нужен -f .

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

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

Рекомендуется заключать каждую переменную в двойные кавычки, если вы точно не знаете, что у вас есть один из редких случаев, когда это не нужно, или один из еще более редких случаев, когда это вредно. (И нет, это не один из них.)

Не могли бы вы уточнить, почему нельзя использовать двойные кавычки? В противном случае я не вижу пользы в комментарии.

Я имел в виду: это не тот редкий случай, когда это не нужно или вредно. Программист оболочки должен привыкнуть заключать (почти) каждую переменную в двойные кавычки; это правило не ограничивается [ . ] .

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

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

Однако, если он возвращает false (или если [ ! -f "$file" ] или ! [ -f "$file" ] возвращает true), существует много разных возможностей:

  • файл не существует
  • файл существует, но не является обычным файлом (может быть устройством, fifo, каталогом, сокетом. )
  • файл существует, но у вас нет разрешения на поиск в родительском каталоге
  • файл существует, но путь к нему слишком длинный
  • файл представляет собой символическую ссылку на обычный файл, но у вас нет разрешения на поиск в некоторых каталогах, участвующих в разрешении символической ссылки.
  • <ли>. любая другая причина, по которой системный вызов stat() может завершиться ошибкой.

Вкратце, это должно быть:

Чтобы точно знать, что файл не существует, нам нужно, чтобы системный вызов stat() возвращал код ошибки ENOENT ( ENOTDIR сообщает нам, что один из компонентов пути не является каталогом — это еще один случай, когда мы можем сказать, что файл не существует по этому пути). К сожалению, команда [ не дает нам знать об этом. Он вернет false, если код ошибки ENOENT, EACCESS (отказано в доступе), ENAMETOOLONG или любой другой.

Проверку [ -e "$file" ] также можно выполнить с помощью ls -Ld -- "$file" > /dev/null . В этом случае ls сообщит вам, почему stat() не удалось, хотя эта информация не может быть легко использована программно:

По крайней мере, ls говорит мне, что ошибка не в том, что файл не существует. Это потому, что он не может сказать, существует файл или нет. Команда [ просто проигнорировала проблему.

В оболочке zsh вы можете запросить код ошибки с помощью специальной переменной $ERRNO после неудачной команды [ и расшифровать это число, используя специальный массив $errnos в модуле zsh/system:

При работе с Bash и сценариями оболочки вам может потребоваться проверить, существует ли каталог или файл в вашей файловой системе.

На основе этого условия вы можете выйти из сценария или, например, отобразить предупреждающее сообщение для конечного пользователя.

Чтобы проверить, существует ли файл или каталог в Bash, вы будете использовать «тесты Bash».

В этом руководстве вы узнаете, как проверить, существует ли файл или каталог в сценарии Bash.

Оглавление

Проверить, существует ли файл

Чтобы проверить, существует ли файл в Bash, вы должны использовать параметр «-f» (для файла) и указать файл, который вы хотите проверить.

Например, предположим, что вы хотите проверить, существует ли файл «/etc/passwd» в вашей файловой системе или нет.

В сценарии вы должны написать следующий оператор if.

Проверка существования файла с использованием более коротких форм

В некоторых случаях вам может быть интересно проверить, существует ли файл непосредственно в вашей оболочке Bash.

Чтобы проверить, существует ли файл в Bash, используя более короткие формы, укажите параметр «-f» в скобках и добавьте команду, которую вы хотите запустить в случае успеха.

Используя пример, использованный ранее, если вы хотите проверить, существует ли файл «/etc/passwd», используя более короткие формы, вы пишете следующую команду

Как же работает эта команда?

Короткие формы тесно связаны со статусами выхода.

Когда вы запускаете команду в Bash, она всегда завершается со статусом ошибки: 0 для ошибки и числа больше 0 для ошибок (1, 2.. 6 и т. д.)

В этом случае синтаксис «&&» проверит, равен ли статус выхода команды слева нулю: если это так, она выполнит команду справа, в противном случае она не будет выполнена. это.

Подсказка: вы можете использовать «echo $», чтобы увидеть статус выхода последней запущенной команды

Проверка нескольких файлов

В некоторых случаях может потребоваться проверить, существует ли в вашей файловой системе несколько файлов.

Чтобы проверить наличие нескольких файлов в Bash, используйте флаг "-f" и укажите файлы для проверки, разделенные оператором "&&".

Проверить, не существует ли файл

С другой стороны, вы можете проверить, не существует ли файл в вашей файловой системе.

Чтобы проверить, не существует ли файл с помощью Bash, вы должны использовать «!» символ, за которым следует параметр «-f» и файл, который вы хотите проверить.

Аналогичным образом вы можете использовать более короткие формы, если хотите быстро проверить, не существует ли файл непосредственно в вашем терминале.

Обратите внимание, что также можно проверить, не существует ли файл, используя «||» оператор.

«||» оператор выполнит команду справа тогда и только тогда, когда команда слева завершится ошибкой (т. е. выйдет со статусом больше нуля).

Чтобы проверить, не существует ли файл, используйте «||» оператор, просто проверьте, существует ли он, используя флаг «-f», и укажите команду для запуска в случае сбоя.

Проверить, существует ли каталог

Чтобы проверить, существует ли каталог в Bash, необходимо использовать параметр «-d» и указать имя каталога, который нужно проверить.

В качестве примера предположим, что вы хотите проверить с помощью Bash, существует ли в вашей системе каталог /etc.

Чтобы проверить его существование, вы должны написать следующий скрипт Bash

При выполнении этого скрипта вы получите следующий вывод

Проверить существование каталога, используя более короткие формы

В некоторых случаях вам может быть интересно проверить, существует ли каталог непосредственно в вашей оболочке Bash.

Чтобы проверить, существует ли каталог в Bash, используя более короткие формы, укажите параметр «-d» в скобках и добавьте команду, которую вы хотите запустить в случае успеха.

Допустим, вы хотите проверить, например, существует ли каталог «/etc».

Используя более короткий синтаксис, вы должны написать следующую команду.

Создание полного сценария Bash

Если вы обнаружите, что несколько раз в день проверяете, существует ли файл (или несколько) в вашей файловой системе или нет, может быть удобно иметь сценарий, который может автоматизировать эту задачу.

В этом разделе вы создадите сценарий Bash, который может принимать несколько имен файлов и возвращать значение независимо от того, существуют они или нет.

В противном случае в стандартном выводе будет отображаться простое уведомление.

Создайте новый скрипт Bash и сделайте его исполняемым с помощью chmod.

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

Сохраните сценарий и добавьте только что созданную папку «bin» в переменную среды PATH.

Теперь, когда ваш скрипт доступен из любой точки системы, вы можете вызвать его и начать проверять, существуют ли файлы или нет.

Вы создали пользовательскую настройку для проверки существования файлов в вашей файловой системе.

Заключение

В этом руководстве вы узнали, как проверить, существует файл или нет, используя тесты Bash и короткий синтаксис Bash.

Аналогичным образом вы узнали, как можно проверить, существует ли каталог.

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

Если вы интересуетесь программированием Bash или системным администрированием Linux, у нас есть целый раздел, посвященный этому на веб-сайте, поэтому обязательно ознакомьтесь с ним!

Читайте также: