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

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

Флаги, также известные как параметры командной строки, представляют собой дополнительные параметры, передаваемые сценарию при его выполнении. Они изменяют поведение скрипта или задают определенные настройки. Перед флагами обычно ставится дефис -для коротких опций или два дефиса --для длинных опций. Например, -hили более длинный--helpможно использовать для отображения справочной информации по сценарию.

Использование флагов дает несколько преимуществ:
1. Настройка. Флаги позволяют пользователям настраивать поведение скрипта в соответствии со своими конкретными требованиями.
2. Гибкость. Предоставляя различные параметры, скрипты могут работать с различными сценариями без необходимости модификации кода. .
3. Удобство использования. Хорошо продуманные флаги делают сценарии более удобными для пользователя, предоставляя четкие инструкции и параметры.

Команда Гетоптс

В Bash getoptscommand — это встроенная утилита для разбора параметров командной строки. Он в основном используется для обработки коротких опций и соответствующих им аргументов. Вот краткий обзор того, как работает getopts:

while getopts "hvf:" flag; do
 case $flag in
   h) # Handle the -h flag
   # Display script help information
   ;;
   v) # Handle the -v flag
   # Enable verbose mode
   ;;
   f) # Handle the -f flag with an argument
   filename=$OPTARG
   # Process the specified file
   ;;
   \?)
   # Handle invalid options
   ;;
 esac
done

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

В приведенном примере getopts "hvf:" flag у нас есть два флага без аргумента h и v и один с аргументом f.

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

Когда команда getopts встречает недопустимую или нераспознанную опцию, она присваивает ? переменной флага, и сценарий входит в блок case \?) для обработки этой ситуации. Как правило, этот блок включает в себя код для отображения сообщения об ошибке, указывающего на то, что была предоставлена ​​недопустимая опция, а также информацию об использовании, чтобы направлять пользователя по правильному использованию.

Помимо переменной flag, используемой в команде getopts, есть еще две важные переменные: $OPTARG и $OPTIND. $OPTARG хранит значение аргумента параметра, связанного с текущим обрабатываемым символом параметра. В приведенном выше примере мы используем его для получения имени файла. $OPTIND — это индексная переменная, представляющая индекс следующего аргумента, который будет обрабатываться getopts.

Однако у getopts есть ограничения, когда дело доходит до обработки длинных опций, таких как --help или --verbose. В таких случаях требуется расширенный подход.

Расширенный подход: обработка коротких и длинных опционов

Для обработки как коротких, так и длинных параметров в сценариях Bash мы можем использовать утилиту shift. Эта утилита сдвигает позиционные параметры скрипта вправо. Лучше всего это описано на примере:

echo "Before shift:"
echo "First argument:  $1"
echo "Second argument: $2"
shift
echo "After shift:"
echo "First argument:  $1"
echo "Second argument: $2"

Вот вывод скрипта, который называется вот так shift-demo one two:

Before shift:
First argument:  one
Second argument: two
After shift:
First argument:  two
Second argument:

Как видите, содержимое $1 заменено на $2, а содержимое $2 исчезло. Мы можем использовать это в цикле while, который обрабатывает аргументы.

while [ $# -gt 0 ]; do
  case $1 in
    # handle options
  esac
  shift
done

Этот цикл while будет перебирать все позиционные аргументы скрипта. Чтобы обрабатывать отдельные флаги, мы можем просто добавить подобные случаи.

-h | --help)
  # Display script help information# Display script help information
  ;;
-v | --verbose)
  # Enable verbose mode
  ;;

В этом случае мы обрабатываем как длинный, так и короткий вариант флага. Однако при работе с флагом -f или --file возникает более сложный сценарий. Поскольку мы не используем getopts, у нас нет доступа к переменной $OPTARG, что требует от нас ручного анализа аргумента, связанного с флагом. Кроме того, если аргумент флага является обязательным, мы должны проверить, предоставил ли его пользователь.

-f | --file)
  if [[ -z "$2" || "$2" == -*]]; then
    echo "File not specified." >&2
    exit 1
  fi
  
  filename=$2
  # Process the specified file  

  shift
  ;;

Если второй позиционный аргумент пуст или начинается с дефиса -, это указывает на то, что пользователь не предоставил никакого дополнительного аргумента или сам аргумент является флагом. В таких случаях мы выводим сообщение об ошибке на стандартную ошибку и выходим из скрипта. И наоборот, если второй позиционный аргумент содержит значение, мы можем обработать его как параметр. Важно отметить, что использование команды shift в операторе case необходимо для обеспечения правильной работы оставшейся части цикла while. Теперь мы можем использовать флаг -f filename или --file filename.

Иногда вы можете встретить флаги со знаком равенства, например --file=filename. Если вы хотите поддерживать этот формат, вы можете расширить вышеупомянутое решение следующим образом. Я не буду подробно объяснять код, но вы можете поэкспериментировать с ним и попытаться понять его в качестве упражнения.

has_argument() {
    [[ ("$1" == *=* && -n ${1#*=}) || ( ! -z "$2" && "$2" != -*)  ]];
}

extract_argument() {
  echo "${2:-${1#*=}}"
}

# In `case` statement
-f | --file*)
  if ! has_argument $@; then
    echo "File not specified." >&2
    usage
    exit 1
  fi

  output_file=$(extract_argument $@)

  shift
  ;;

Обратите внимание, что в этой настройке вы можете использовать формат --file=filename для указания файла, но вы не можете использовать формат -f=filename.

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

*)
  echo "Invalid option: $1" >&2
  exit 1
  ;;

Вот вся программа для ознакомления:

#!/bin/bash

# Default variable values
verbose_mode=false
output_file=""

# Function to display script usage
usage() {
 echo "Usage: $0 [OPTIONS]"
 echo "Options:"
 echo " -h, --help      Display this help message"
 echo " -v, --verbose   Enable verbose mode"
 echo " -f, --file      FILE Specify an output file"
}

has_argument() {
    [[ ("$1" == *=* && -n ${1#*=}) || ( ! -z "$2" && "$2" != -*)  ]];
}

extract_argument() {
  echo "${2:-${1#*=}}"
}

# Function to handle options and arguments
handle_options() {
  while [ $# -gt 0 ]; do
    case $1 in
      -h | --help)
        usage
        exit 0
        ;;
      -v | --verbose)
        verbose_mode=true
        ;;
      -f | --file*)
        if ! has_argument $@; then
          echo "File not specified." >&2
          usage
          exit 1
        fi

        output_file=$(extract_argument $@)

        shift
        ;;
      *)
        echo "Invalid option: $1" >&2
        usage
        exit 1
        ;;
    esac
    shift
  done
}

# Main script execution
handle_options "$@"

# Perform the desired actions based on the provided flags and arguments
if [ "$verbose_mode" = true ]; then
 echo "Verbose mode enabled."
fi

if [ -n "$output_file" ]; then
 echo "Output file specified: $output_file"
fi

Заключение

Обработка флагов в сценариях Bash позволяет пользователям настраивать поведение сценария и обеспечивает большую гибкость и удобство использования. Команда getopts подходит для обработки коротких опций, а расширенный подход позволяет обрабатывать как короткие, так и длинные опции. Благодаря включению функции использования и реализации обработки ошибок сценарии становятся более удобными для пользователя. С помощью этих методов вы можете улучшить свои сценарии Bash и сделать их более универсальными и адаптируемыми к различным сценариям.

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