В скриптах Bash очень часто проверяется существование файла или каталога.

Как проверить существование файла или каталога с помощью Bash?

В Linux все является файлом. Вы можете использовать команду test, за которой следует оператор -f, чтобы проверить, существует ли файл и является ли он обычным файлом. Таким же образом команда test, за которой следует оператор -d, позволяет проверить, существует ли файл и является ли он каталогом. Команда test также может быть представлена ​​одинарными квадратными скобками [ ] или двойными квадратными скобками [[ ]].

Теперь, когда вы знаете, как проверить наличие файла или каталога в системе Linux с помощью Bash, давайте рассмотрим несколько практических примеров.

Например, вы можете проверить:

  • если файл журнала уже существует, и создайте его, если его нет…
  • если каталог, необходимый для корректного выполнения вашего скрипта, существует…

И это всего лишь два из сотен сценариев, в которых вам, возможно, захочется это проверить.

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

Чтобы проверить, существует ли файл в системе Linux, можно использовать команду test, представленную квадратными скобками, за которыми следует флаг -f:

[ -f filename ]

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

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

Булевое выражение может иметь только два значения: true или false. Булевы выражения используются в Bash (и в других языках программирования) для выполнения различных команд в зависимости от значения условия.

Следующий скрипт является примером того, как проверить, существует ли файл /var/log/install.log:

#!/bin/bash
   
FILENAME="/var/log/install.log"
 
if [ -f "$FILENAME" ]
then
  echo "$FILENAME exists"
fi 

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

Если файл существует и это обычный файл, мы используем команду echo, чтобы вывести «/var/log/install.log существует», как вы можете видеть ниже:

localhost$./file_exists.sh 
/var/log/install.log exists 

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

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

Примечание: При использовании выражения [-f имя_файла] убедитесь, что после открывающейся квадратной скобки и перед закрывающейся квадратной скобкой есть пробел.

Что произойдет, если мы забудем пробел после открывающейся квадратной скобки?

localhost$./file_exists.sh 
./file_exists.sh: line 5: [-f: command not found 

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

Теперь давайте посмотрим, как проверить, существует ли каталог.

Проверьте, не является ли файл пустым

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

Для этого мы по-прежнему можем использовать тестовое выражение, но на этот раз с флагом -s.

Я создам два файла в текущем каталоге с помощью команд touch и echo. Первый файл (testfile1) пустой, а второй файл (testfile2) не пустой.

(localhost) $ touch testfile1
(localhost) $ echo "Test file" > testfile2

Давайте напишем скрипт под названием check_empty_files.sh, вот код:

#!/bin/bash
  
if [ -s testfile1 ]; then
    echo "testfile1 is not empty"
else
    echo "testfile1 is empty"
fi

if [ -s testfile2 ]; then
    echo "testfile2 is not empty"
else
    echo "testfile2 is empty"
fi

Итак, как вы видите, я использую оператор test с флагом -s. И вот вывод скрипта:

(localhost) $./check_empty_files.sh 
testfile1 is empty
testfile2 is not empty

Скрипт работает так, как и ожидалось, и определяет, какой файл пуст, а какой нет.

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

Знаете как?

Проверка существования каталога с помощью Bash

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

[ -d dirname ]

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

Теперь давайте рассмотрим пример скрипта, который проверяет существование каталога /var/log/:

#!/bin/bash
   
DIRNAME="/var/log/"
 
if [ -d "$DIRNAME" ]
then
  echo "$DIRNAME exists"
fi

А вот и результат работы скрипта:

localhost$./dir_exists.sh 
/var/log/ exists 

Правило о пробеле после открывающейся квадратной скобки и перед закрывающейся квадратной скобкой действует и в этом случае.

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

Вложенные тестовые выражения Bash

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

Мы можем вкладывать их в зависимости от логики, которую хотим реализовать в нашем скрипте.

Мы напишем скрипт под названием dir_file_exist.sh, который:

  1. Проверяет, существует ли каталог test_dir в текущем каталоге.
  2. Создает каталог, если он не существует, и выводит в оболочке сообщение «Directory test_dir created».
  3. Проверяет наличие файла test_file в каталоге test_dir.
  4. Создайте файл, если он не существует, с помощью команды touch.

Вот сценарий:

#!/bin/bash
   
DIRNAME="test_dir"
FILENAME="test_file"
  
if [! -d "$DIRNAME" ]
then
  mkdir $DIRNAME
  echo "Directory $DIRNAME created"
  if [! -f "$FILENAME" ]
  then
    touch $DIRNAME/$FILENAME
    echo "File $DIRNAME/$FILENAME created"
  else
    echo "File $DIRNAME/$FILENAME exists"
  fi
else
  echo "Directory $DIRNAME exists"
fi 

Восклицательный знак используется как отрицание выражений -d и -f.

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

Итак, пришло время выполнить скрипт и посмотреть, делает ли он то, что мы ожидаем:

Сценарий, запуск №1

localhost$./dir_file_exist.sh 
Directory test_dir created
File test_dir/test_file created 

Мы видим, что каталог test_dir и файл test_dir/test_file были созданы, поскольку они не существовали:

localhost$ ls -al
total 8
drwxr-xr-x   4 testuser  staff  128 19 Mar 01:43.
drwxr-xr-x  10 testuser  staff  320 19 Mar 01:43..
-rwxr-xr-x   1 testuser  staff  341 19 Mar 01:43 dir_file_exist.sh
drwxr-xr-x   3 testuser  staff   96 19 Mar 01:43 test_dir

localhost$ ls -al test_dir/
 total 0
 drwxr-xr-x  3 testuser  staff   96 19 Mar 01:43.
 drwxr-xr-x  4 testuser  staff  128 19 Mar 01:43..
 -rw-r--r--  1 testuser  staff    0 19 Mar 01:43 test_file 

Давайте выполним сценарий еще раз…

Сценарий №2

localhost$./dir_file_exist.sh 
Directory test_dir exists 

На этот раз скрипт просто выполняет ветвь else для теста, который проверяет, существует ли каталог test_dir.

Вот почему мы видим сообщение «Каталог test_dir существует», а затем скрипт завершает свое выполнение.

Другие выражения Bash Test

Тестовые выражения, которые мы видели, — это всего лишь два примера того, что предоставляет Linux.

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

Тестовое выражениеЗначение
[ -f <файл> ]Истина, если файл существует и это обычный файл
[ -d <файл> ]Истина, если файл существует и является каталогом
[ -s <файл> ]Истина, если файл существует и его размер больше нуля
[ -L <файл> ]Истина, если файл существует и является символической ссылкой
[ -p <файл> ]True, если файл является каналом имен (FIFO)
[ -b <файл> ]Истина, если файл является блочным специальным устройством

Вы также можете использовать тестовое выражение для сравнения строк и целых чисел. Что-нибудь для другого дня!

Заключение

В заключение следует отметить, что этот урок показал вам:

  • Проверьте существование файла или каталога с помощью Bash.
  • Используйте if else для выполнения различных действий в зависимости от значения выражения, используемого для проверки существования файла или каталога.
  • Напишите вложенные операторы if else.
  • Добавьте восклицательный знак к проверочным выражениям -f или -d, чтобы проверить, существует ли файл или каталог (значение восклицательного знака в Bash — отрицание выражения, которое следует за ним).

Имеет смысл? 🙂

Written by Иван Васильков

Системный администратор и DevOps с опытом 10+ лет.