Поиск по сайту:

Как проверить, существует ли файл в сценариях Linux Bash


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

Ничего не предполагай

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

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

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

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

Диапазон тестов

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

  • -b: возвращает true, если файл является блочным специальным файлом.
  • -c: возвращает true, если файл содержит специальные символы.
  • -d: возвращает значение true, если «файл» является каталогом.
  • -e: возвращает true, если файл существует.
  • -f: возвращает true, если файл существует и является обычным файлом.
  • -g: возвращает значение true, если файл имеет набор разрешений setgid (chmod g+).
  • -h: возвращает true, если файл является символической ссылкой.
  • -L: возвращает true, если файл является символической ссылкой.
  • -k: возвращает true, если установлен фиксированный бит (chmod +t).
  • -p: возвращает true, если файл является именованным каналом.
  • -r: возвращает true, если файл доступен для чтения.
  • -s: возвращает значение true, если файлы существуют и не пусты.
  • -S: возвращает true, если файл является сокетом.
  • -t: возвращает true, если дескриптор файла открыт в терминале.
  • -u: возвращает true, если файл имеет набор разрешений setuid (chmod u+).
  • -w: возвращает true, если файл доступен для записи.
  • -x: возвращает true, если файл является исполняемым.
  • -O: возвращает true, если вы являетесь владельцем.
  • -G: возвращает true, если принадлежит вашей группе.
  • -N: возвращает true, если файл был изменен с момента последнего чтения.
  • !: логический оператор НЕ.
  • &&: логический оператор И.
  • ||: логический оператор ИЛИ.

Список начинается с -b, поскольку тест -a устарел и заменен тестом -e.

Использование тестов в сценариях

Общий оператор file test if представляет собой простую конструкцию сценария. Сравнение внутри двойных скобок «[[ ]]» использует тест -f, чтобы определить, существует ли обычный файл с таким именем.

Скопируйте текст этого скрипта в редактор и сохраните его в файл с именем «script1.sh» и используйте chmod, чтобы сделать его исполняемым.

#!/bin/bash

if [[ -f $1 ]] 

then 

  echo "The file $1 exists." 

else 

  echo "The file $1 cannot be found." 

fi

Вы должны передать имя файла сценарию в командной строке.

chmod +x script1.sh

Вам нужно будет сделать это с каждым скриптом, если вы хотите попробовать другие примеры из статьи.

Давайте попробуем скрипт на простом текстовом файле.

./script1.sh test-file.txt

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

./script1.sh test-file.txt

В реальной ситуации ваш сценарий должен был бы предпринять любое подходящее действие. Возможно, он помечает ошибку и останавливается. Может быть, он создает файл и продолжает. Он может скопировать что-то из резервного каталога, чтобы заменить отсутствующий файл. Все зависит от цели скрипта. Но, по крайней мере, теперь скрипт может принимать решение, зная, присутствует файл или нет.

Флаг -f проверяет наличие файла и является ли он «обычным». Другими словами, это не то, что кажется файлом, но таковым не является, например, файл устройства.

Мы воспользуемся ls, чтобы убедиться, что файл «/dev/random» существует, а затем посмотрим, что с ним сделает скрипт.

ls -lh /dev/random
./script /dev/random

Поскольку наш скрипт тестирует обычные файлы, а «/dev/random» — это файл устройства, тест завершается неудачно. Очень часто, чтобы понять, существует ли файл, вам нужно тщательно выбрать, какой тест вы используете, или вам нужно использовать несколько тестов.

Это «script2.sh», который проверяет обычные файлы и файлы символьных устройств.

#!/bin/bash

if [[ -f $1 ]]
then
  echo "The file $1 exists."
else
  echo "The file $1 is missing or not a regular file."
fi

if [[ -c $1 ]]
then
  echo "The file $1 is a character device file."
else
  echo "The file $1 is missing or not a special file." 
fi

Если мы запустим этот скрипт в файле устройства «/dev/random», первый тест, как мы и ожидали, завершится неудачно, а второй завершится успешно. Он распознает файл как файл устройства.

./script2.sh /dev/random

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

./script2.sh /dev/sda

Мы можем использовать логический оператор ИЛИ и включить еще один тест во второй оператор if. На этот раз, независимо от того, является ли файл файлом символьного устройства или файлом блочного устройства, тест вернет значение true. Это «script3.sh».

#!/bin/bash

if [[ -f $1 ]]
then
  echo "The file $1 exists."
else
  echo "The file $1 is missing or not a regular file."
fi

if [[ -c $1 || -b $1 ]]
then
  echo "The file $1 is a character or block device file."
else
  echo "The file $1 is missing or not a special file." 
fi

Этот сценарий распознает файлы как символьных, так и блочных устройств.

./script3.sh /dev/random
./script3.sh /dev/sda

Если вам важно различать разные типы файлов устройств, вы можете использовать вложенные операторы if . Это «script4.sh».

#!/bin/bash

if [[ -f $1 ]]
then
  echo "The file $1 exists."
else
  echo "The file $1 is missing or not a regular file."
fi

if [[ -c $1 ]]
then
  echo "The file $1 is a character device file."
else
  if [[ -b $1 ]]
  then
    echo "The file $1 is a block device file." 
  else
    echo "The file $1 is missing or not a device file."
  fi
fi

Этот сценарий распознает и классифицирует файлы как символьных, так и блочных устройств.

./script4.sh /dev/random
./script4.sh /dev/sda

С помощью логического оператора И мы можем проверить сразу несколько характеристик. Это «script5.sh». Он проверяет, что файл существует и скрипт имеет права на чтение и для него.

#!/bin/bash

if [[ -f $1 && -r $1 && -w $1 ]]
then
  echo "The file $1 exists and we have read/write permissions."
else
  echo "The file $1 is missing, not a regular file, or we can't read/write to it."
fi

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

./script5.sh .bashrc
./script5.sh /etc/fstab

Чтобы проверить существование каталога, используйте тест -d. Это «script6.sh». Это часть сценария резервного копирования. Первое, что он делает, это проверяет, существует ли каталог, переданный в командной строке, или нет. Он использует логический оператор NOT ! в тесте инструкции if.

#!/bin/bash

if [[ ! -d $1 ]]
then
  echo "Creating backup directory:" $1
  mkdir $1

  if [[ ! $? -eq 0 ]]
  then
    echo "Couldn't create backup directory:" $1
    exit
  fi
else
  echo "Backup directory exists."
fi

# continue with file backup
echo "Backing up to: "$1

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

Мы запустим скрипт, а затем проверим с помощью ls и опции -d (каталог), существует ли резервный каталог.

./script6.sh Documents/project-backup
ls -d Documents/project-backup

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

./script6.sh

Сценарий находит каталог и переходит к выполнению резервного копирования.

Тестируйте, не предполагайте

Рано или поздно предположения приведут к плохим последствиям. Сначала протестируйте и реагируйте соответственно.

Знание - сила. Используйте тесты, чтобы дать вашим скриптам необходимые знания.