Использование Ассоциативных Массивов Bash в Скриптах Shell

ShellShellBeginner
Практиковаться сейчас

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

Введение

Этот учебник проведет вас через процесс понимания и использования ассоциативных массивов (key-value arrays) в Bash для ваших скриптов. Ассоциативные массивы - это мощные структуры данных, которые позволяют хранить и извлекать данные, используя описательные ключи вместо числовых индексов.

К концу этого учебника вы сможете создавать, манипулировать и использовать ассоциативные массивы в ваших скриптах Bash, чтобы более эффективно организовывать данные и решать задачи, которые были бы сложны с традиционными числовыми массивами.

Создание вашего первого ассоциативного массива Bash

Ассоциативные массивы (key-value arrays) в Bash позволяют вам связывать значения с определенными ключами, аналогично словарям в Python или объектам в JavaScript. Это делает их идеальными для хранения структурированных данных, где элементы идентифицируются по именам, а не по позициям.

Основной синтаксис

Чтобы работать с ассоциативными массивами в Bash, вы должны сначала объявить их, используя опцию -A:

declare -A myarray

Это создает пустой ассоциативный массив с именем myarray. Флаг -A специально сообщает Bash, что это ассоциативный (key-value) массив.

Добавление элементов в массив

Давайте создадим ассоциативный массив для хранения информации о разных фруктах:

  1. Откройте новый терминал в WebIDE, если он еще не открыт
  2. Создайте новый файл скрипта, нажав "File > New File" в WebIDE
  3. Сохраните файл как fruit_array.sh в каталоге /home/labex/project
  4. Добавьте следующий код в файл:
#!/bin/bash

## Declare a key-value array
declare -A fruits

## Add elements to the array
fruits["apple"]="red"
fruits["banana"]="yellow"
fruits["grape"]="purple"
fruits["orange"]="orange"

## Print a specific element
echo "The color of an apple is ${fruits["apple"]}"

## Print all values
echo "All fruit colors: ${fruits[@]}"

## Print all keys
echo "All fruits: ${!fruits[@]}"
  1. Сохраните файл (Ctrl+S или File > Save)
  2. Сделайте скрипт исполняемым с помощью следующей команды в терминале:
chmod +x fruit_array.sh
  1. Запустите скрипт:
./fruit_array.sh

Вы должны увидеть вывод, похожий на этот:

The color of an apple is red
All fruit colors: red yellow purple orange
All fruits: apple banana grape orange

Понимание вывода

  • ${fruits["apple"]}: Этот синтаксис извлекает значение, связанное с ключом "apple"
  • ${fruits[@]}: Это возвращает все значения в массиве
  • ${!fruits[@]}: Символ ! перед именем массива возвращает все ключи в массиве

Ассоциативные массивы Bash позволяют вам получать доступ к данным напрямую, используя понятные имена, а не запоминать числовые позиции, что делает ваши скрипты более читаемыми и удобными в обслуживании.

Манипулирование ассоциативными массивами Bash

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

Создание нового скрипта

  1. Создайте новый файл с именем array_operations.sh в каталоге /home/labex/project
  2. Добавьте следующий код в файл:
#!/bin/bash

## Declare a key-value array
declare -A user_info

## Add initial elements
user_info["name"]="John Doe"
user_info["email"]="[email protected]"
user_info["age"]="30"
user_info["city"]="New York"

## Display initial array content
echo "--- Initial user information ---"
for key in "${!user_info[@]}"; do
  echo "$key: ${user_info[$key]}"
done

## Modify an existing value
user_info["age"]="31"

## Add a new key-value pair
user_info["country"]="USA"

## Check if a key exists
if [[ -v user_info["email"] ]]; then
  echo -e "\nEmail exists: ${user_info["email"]}"
else
  echo -e "\nEmail does not exist"
fi

## Remove an element
unset 'user_info[city]'

## Display the modified array
echo -e "\n--- Modified user information ---"
for key in "${!user_info[@]}"; do
  echo "$key: ${user_info[$key]}"
done

## Count the number of elements
echo -e "\nNumber of elements: ${#user_info[@]}"
  1. Сохраните файл (Ctrl+S или File > Save)
  2. Сделайте скрипт исполняемым:
chmod +x array_operations.sh
  1. Запустите скрипт:
./array_operations.sh

Вы должны увидеть вывод, похожий на этот:

--- Initial user information ---
name: John Doe
email: [email protected]
age: 30
city: New York

Email exists: [email protected]

--- Modified user information ---
name: John Doe
country: USA
email: [email protected]
age: 31

Number of elements: 4

Объяснение ключевых операций

  • Изменение значений: Просто присвойте новое значение существующему ключу: user_info["age"]="31"
  • Добавление новых элементов: Используйте тот же синтаксис, что и при начальном присвоении: user_info["country"]="USA"
  • Проверка существования ключа: Используйте оператор теста -v: [[ -v user_info["email"] ]]
  • Удаление элементов: Используйте команду unset: unset 'user_info[city]'
  • Подсчет элементов: Используйте ${#array[@]}, чтобы получить количество элементов
  • Итерация по элементам: Используйте цикл for с ${!array[@]}, чтобы получить все ключи

Обратите внимание, как пара ключ-значение city удалена в измененном выводе, и добавлена новая пара ключ-значение country. Также значение age было обновлено с 30 до 31.

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

Создание практического менеджера конфигурации

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

Шаг 1: Создание файла конфигурации

Сначала давайте создадим файл конфигурации с некоторыми примерами настроек:

  1. Создайте новый файл с именем app_config.txt в каталоге /home/labex/project
  2. Добавьте следующее содержимое в файл:
database_host=localhost
database_port=3306
database_user=admin
database_password=secret123
app_name=MyAwesomeApp
debug_mode=true
max_connections=100
  1. Сохраните файл

Шаг 2: Создание скрипта менеджера конфигурации

Теперь давайте создадим скрипт, который будет читать этот файл конфигурации и хранить его содержимое в ассоциативном массиве:

  1. Создайте новый файл с именем config_manager.sh в каталоге /home/labex/project
  2. Добавьте следующий код в файл:
#!/bin/bash

## Define the path to the configuration file
CONFIG_FILE="/home/labex/project/app_config.txt"

## Declare a key-value array for the configuration
declare -A config

## Function to load configuration from file
load_config() {
  local file=$1

  ## Check if the file exists
  if [[ ! -f "$file" ]]; then
    echo "Error: Configuration file '$file' not found."
    return 1
  fi

  ## Read the file line by line
  while IFS='=' read -r key value; do
    ## Skip empty lines and comments
    if [[ -z "$key" || "$key" == \#* ]]; then
      continue
    fi

    ## Store the key-value pair in the array
    config["$key"]="$value"
  done < "$file"

  echo "Configuration loaded successfully from '$file'"
  return 0
}

## Function to get a configuration value
get_config() {
  local key=$1
  local default=$2

  ## Check if the key exists
  if [[ -v config["$key"] ]]; then
    echo "${config["$key"]}"
  else
    echo "$default"
  fi
}

## Function to display all configuration
display_config() {
  echo "--- Configuration Settings ---"
  for key in "${!config[@]}"; do
    echo "$key = ${config[$key]}"
  done
}

## Load the configuration
load_config "$CONFIG_FILE"

## Display all configuration settings
display_config

## Example of getting specific configuration values
echo -e "\n--- Example Usage ---"
db_host=$(get_config "database_host" "127.0.0.1")
db_port=$(get_config "database_port" "5432")
db_user=$(get_config "database_user" "root")
db_pass=$(get_config "database_password" "")
app_name=$(get_config "app_name" "DefaultApp")
debug_mode=$(get_config "debug_mode" "false")

echo "Database connection: $db_user@$db_host:$db_port"
echo "Application name: $app_name"
echo "Debug mode: $debug_mode"

## Example of getting a non-existent value (will use default)
timeout=$(get_config "connection_timeout" "30")
echo "Connection timeout: $timeout (default value used)"
  1. Сохраните файл (Ctrl+S или File > Save)
  2. Сделайте скрипт исполняемым:
chmod +x config_manager.sh
  1. Запустите скрипт:
./config_manager.sh

Вы должны увидеть вывод, похожий на этот:

Configuration loaded successfully from '/home/labex/project/app_config.txt'
--- Configuration Settings ---
database_host = localhost
database_port = 3306
database_user = admin
database_password = secret123
app_name = MyAwesomeApp
debug_mode = true
max_connections = 100

--- Example Usage ---
Database connection: admin@localhost:3306
Application name: MyAwesomeApp
Debug mode: true
Connection timeout: 30 (default value used)

Понимание менеджера конфигурации

Скрипт, который вы создали, выполняет несколько важных действий:

  1. Он читает пары ключ-значение из файла конфигурации
  2. Он хранит эти пары в ассоциативном массиве
  3. Он предоставляет функции для:
    • Загрузки конфигурации из файла
    • Получения конкретных значений конфигурации с резервными значениями по умолчанию
    • Отображения всех настроек конфигурации

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

  • Централизованная конфигурация: Все настройки находятся в одном месте
  • Значения по умолчанию: Если настройка отсутствует, можно использовать значение по умолчанию
  • Легкий доступ: Доступ к настройкам можно получить по имени
  • Гибкость: Конфигурацию можно обновить, не изменяя скрипт

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

Создание скрипта с меню на основе ассоциативных массивов

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

Создание системы меню

  1. Создайте новый файл с именем menu_system.sh в каталоге /home/labex/project
  2. Добавьте следующий код в файл:
#!/bin/bash

## Declare a key-value array for menu options
declare -A menu_options
menu_options["1"]="Display system information"
menu_options["2"]="Check disk usage"
menu_options["3"]="List running processes"
menu_options["4"]="View network connections"
menu_options["q"]="Quit"

## Declare a key-value array for commands to execute
declare -A menu_commands
menu_commands["1"]="display_system_info"
menu_commands["2"]="check_disk_usage"
menu_commands["3"]="list_processes"
menu_commands["4"]="view_network"

## Function to display system information
display_system_info() {
  echo -e "\n--- System Information ---"
  echo "Hostname: $(hostname)"
  echo "Kernel version: $(uname -r)"
  echo "System uptime: $(uptime -p)"
  echo "CPU information: $(grep 'model name' /proc/cpuinfo | head -1 | cut -d ':' -f 2 | xargs)"
  echo "Total memory: $(free -h | grep Mem | awk '{print $2}')"
}

## Function to check disk usage
check_disk_usage() {
  echo -e "\n--- Disk Usage ---"
  df -h | grep -v tmp
}

## Function to list running processes
list_processes() {
  echo -e "\n--- Top 10 Processes by Memory Usage ---"
  ps aux --sort=-%mem | head -11
}

## Function to view network connections
view_network() {
  echo -e "\n--- Active Network Connections ---"
  netstat -tuln | grep LISTEN
}

## Function to display the menu
display_menu() {
  echo -e "\n=== System Utility Menu ==="
  for key in 1 2 3 4 q; do
    echo "$key. ${menu_options[$key]}"
  done
  echo -e "\nPlease enter your choice:"
}

## Main loop
while true; do
  ## Display the menu
  display_menu

  ## Read user choice
  read -r choice

  ## Check if choice is valid
  if [[ -v menu_options["$choice"] ]]; then
    ## Exit if user chose quit
    if [[ "$choice" == "q" ]]; then
      echo "Exiting. Goodbye!"
      exit 0
    fi

    ## Execute the corresponding command
    if [[ -v menu_commands["$choice"] ]]; then
      ## Call the function associated with the choice
      ${menu_commands["$choice"]}
    fi
  else
    echo "Invalid option. Please try again."
  fi

  ## Pause for user to read output
  echo -e "\nPress Enter to continue..."
  read -r
done
  1. Сохраните файл (Ctrl+S или File > Save)
  2. Сделайте скрипт исполняемым:
chmod +x menu_system.sh
  1. Запустите скрипт:
./menu_system.sh
  1. Попробуйте разные пункты меню, вводя соответствующий номер, затем нажмите Enter, когда появится запрос, чтобы вернуться в меню. Введите q, чтобы выйти из программы, когда закончите.

Понимание системы меню

Этот скрипт демонстрирует несколько продвинутых способов использования ассоциативных массивов:

  1. Пункты меню: Массив menu_options сопоставляет номера опций с описательным текстом
  2. Сопоставление команд: Массив menu_commands сопоставляет номера опций с именами функций
  3. Динамическое выполнение: Скрипт использует значение из одного массива, чтобы определить, какую функцию вызывать

Преимущества использования ассоциативных массивов в этой системе меню включают:

  • Удобство обслуживания: Добавление или изменение пунктов меню требует только обновления массивов
  • Читаемость: Код четко показывает, какая команда соответствует какому пункту меню
  • Гибкость: Вы можете легко переупорядочить пункты меню, не изменяя вызовы функций

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

Основные выводы

В течение этого руководства вы узнали:

  1. Как создавать и инициализировать ассоциативные массивы в Bash
  2. Как получать доступ, изменять и удалять элементы из ассоциативных массивов
  3. Как перебирать ключи и значения в ассоциативном массиве
  4. Как использовать ассоциативные массивы для хранения данных конфигурации
  5. Как создать интерактивную систему меню, используя ассоциативные массивы

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

Резюме

В этом руководстве вы изучили мощь и универсальность ассоциативных массивов (key-value arrays) в Bash. Начиная с основ, вы узнали, как создавать и получать доступ к ассоциативным массивам, а затем перешли к более сложным операциям, таким как изменение, добавление и удаление элементов.

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

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

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