Эффективно обрабатывайте строки в сценариях автоматизации с помощью этих синтаксисов.
Bash стал языком автоматизации по умолчанию для каждой Unix-подобной или основанной на Unix операционной системе. Каждый системный администратор, инженер DevOps и программист обычно использует Bash для написания сценариев оболочки с повторяющимися последовательностями команд. Сценарии Bash обычно содержат команды, запускающие другие двоичные файлы программ. В большинстве сценариев нам может потребоваться обработать данные и создать логический поток в сценарии оболочки. Таким образом, нам часто приходится добавлять условные операторы и операторы обработки текста в наши сценарии оболочки.
Традиционные сценарии Bash и прошлые программисты, которые использовали более старые версии интерпретатора Bash, обычно использовали команды awk
, sed
, tr
и cut
для работы с текстом. Это отдельные программы. Несмотря на то, что эти программы обработки текста предлагают хорошие возможности, они замедляют ваш сценарий Bash, поскольку каждая конкретная команда имеет значительное время запуска процесса. Современные версии Bash предлагают встроенные функции обработки текста с помощью известной функции расширения параметров.
В этой статье я объясню некоторые встроенные синтаксис манипулирования строками, которые вы можете использовать для продуктивной обработки текста в сценариях Bash.
Извлечение и замена подстроки
Подстрока относится к заразному сегменту или части конкретной строки. В различных сценариях сценариев нам нужно извлекать подстроки из сегментов строки. Например, вам может понадобиться получить только сегмент имени файла из полного имени файла, состоящего из расширения. Кроме того, вам может понадобиться заменить подстроки определенными сегментами строки (т. е. изменить расширение имени файла).
Извлечение подстроки очень просто, если указать позицию и длину символа:
#!/bin/bash str="2023-10-12" echo "${str:5:2}" # 10 echo "${str::4}" # 2023 echo "2022-${str:5}" # 2022-10-12
Вы даже можете выполнять вычисления подстроки с правой стороны, как показано ниже:
#!/bin/bash str="backup.sql" echo "original${str:(-4)}" # original.sql
Bash также предлагает продуктивный встроенный синтаксис для замены подстроки:
#!/bin/bash str="obin-linux_x64_bin" echo "${str/x64/armhf}" # obin-linux_armhf_bin echo "${str/bin/dist}" # odist-linux_x64_bin echo "${str//bin/dist}" # odist-linux_x64_dist
При работе с некоторыми строками, такими как имена файлов, пути и т. д., вам может потребоваться заменить префиксы и суффиксы строк. Хорошим примером является замена расширения файла другим расширением. Посмотрите на следующий пример:
#!/bin/bash str="db_config_backup.zip" echo "${str/%.zip/.conf}" # db_config_backup.conf echo "${str/#db/settings}" # settings_config_backup.zip
В приведенных выше примерах замены подстроки мы использовали точный сегмент подстроки для сопоставления, но вы также можете использовать часть подстроки, используя подстановочный знак *
следующим образом:
#!/bin/bash str="db_config_backup.zip" echo "${str/%.*/.bak}" # db_config_backup.bak echo "${str/#*_/new}" # newbackup.zip
Приведенный выше подход полезен, если вы не знаете точную подстроку для поиска.
Совпадения регулярных выражений, извлечения и замены
Как уже известно многим пользователям Unix или GNU/Linux, можно использовать grep
и sed
для поиска текста на основе регулярных выражений. sed
помогает нам выполнять замену регулярных выражений. Вы можете использовать встроенные функции регулярных выражений Bash для обработки текста быстрее, чем эти внешние двоичные файлы.
Вы можете выполнить сопоставление регулярного выражения с условием if и оператором =~
, как показано в следующем фрагменте кода:
#!/bin/bash str="db_backup_2003.zip" if [[ $str =~ 200[0-5]+ ]]; then echo "regex_matched" fi
Вы также можете заменить оператор if на встроенное условие, если хотите:
[[ $str =~ 200[0-5]+ ]] && echo "regex_matched"
Как только интерпретатор Bash выполняет сопоставление с регулярным выражением, он обычно сохраняет все совпадения в переменной оболочки BASH_REMATCH
. Эта переменная является массивом только для чтения и хранит все совпадающие данные в первом индексе. Если вы используете подшаблоны, Bash постепенно сохраняет эти совпадения в других индексах:
#!/bin/bash str="db_backup_2003.zip" if [[ $str =~ (200[0-5])(.*)$ ]]; then echo "${BASH_REMATCH[0]}" # 2003.zip echo "${BASH_REMATCH[1]}" # 2003 echo "${BASH_REMATCH[2]}" # .zip fi
Помните, мы использовали подстановочные знаки с предыдущим соответствием подстроки? Точно так же можно использовать определения регулярных выражений внутри расширений параметров, как показано в следующем примере:
#!/bin/bash str="db_backup_2003.zip" re="200[0-3].zip" echo "${str/$re/new}.bak" # db_backup_new.bak
Методы удаления подстроки
Нам часто нужно предварительно обрабатывать текстовые сегменты, удаляя ненужные подстроки во многих требованиях к обработке текста. Например, если вы извлекаете номер версии с префиксом v
и некоторыми номерами сборки и хотите найти основной номер версии, вам придется удалить некоторые подстроки. Вы можете использовать тот же синтаксис замены подстроки, но опустить параметр строки замены для удаления строки следующим образом:
#!/bin/bash str="ver5.02-2224.e2" ver="${str#ver}" echo $ver # 5.02-2224.e2 maj="${ver/.*}" echo $maj # 5
В приведенном выше примере мы использовали точную подстроку и подстановочный знак для удаления подстроки, но вы также можете использовать регулярные выражения. Проверьте, как извлечь чистый номер версии без лишних символов:
#!/bin/bash str="ver5.02-2224_release" ver="${str//[a-z_]}" echo $ver # 5.02-2224
Преобразования регистра и переменные, основанные на регистре
Даже стандартный язык C предлагает функцию для преобразования регистра символа. Почти все современные языки программирования предоставляют встроенные функции для преобразования регистра. В качестве командного языка Bash не предлагает функций для преобразования регистра, но предоставляет нам возможности преобразования регистра посредством раскрытия параметров и объявления переменных.
Посмотрите на следующий пример, который преобразует регистр букв:
#!/bin/bash str="Hello Bash!" lower="${str,,}" upper="${str^^}" echo $lower # hello bash! echo $upper # HELLO BASH!
Вы также можете использовать верхний или нижний регистр только для первого символа конкретной строки следующим образом:
#!/bin/bash ver1="V2.0-release" ver2="v4.0-release" echo "${ver1,}" # v2.0-release echo "${ver2^}" # V4.0-release
Если вам нужно сделать определенную переменную строго прописной или строчной, вам не нужно постоянно запускать функцию преобразования регистра. Вместо этого вы можете добавить атрибуты case к определенной переменной с помощью встроенной команды declare
, как показано в следующем примере:
#!/bin/bash declare -l ver1 declare -u ver2 ver1="V4.02.2" ver2="v2.22.1" echo $ver1 # v4.02.2 echo $ver2 #V2.22.1
Приведенные выше переменные ver1
и ver2
получают атрибут case во время объявления, поэтому всякий раз, когда вы присваиваете значение определенной переменной, Bash преобразует текстовый регистр на основе атрибутов переменных.
Разделение строк (преобразование строки в массив)
Bash позволяет определять индексированные и ассоциативные массивы с помощью встроенного declare
. Большинство языков программирования общего назначения предлагают метод split
в строковом объекте или через функцию стандартной библиотеки (функция strings.Split
в Go). Вы можете разделить строку и создать массив несколькими способами в Bash. Например, мы можем изменить IFS
на нужный разделитель и использовать встроенный read
. Или мы можем использовать команду tr
с циклом и построить массив. Или использование встроенного расширения параметров — еще один подход. В Bash так много подходов к разбиению строк.
Использование IFS
и read
— один из самых простых и безошибочных способов разбить строку:
#!/bin/bash str="C,C++,JavaScript,Python,Bash" IFS=',' read -ra arr <<< "$str" echo "${#arr[@]}" # 5 echo "${arr[0]}" # C echo "${arr[4]}" # Bash
Приведенный выше фрагмент кода использует ,
в качестве разделителя разделения и использует встроенную команду read
для создания массива на основе IFS
.
Несмотря на то, что есть простейшие способы обработки разделения без read
, убедитесь, что нет скрытых проблем. Например, следующая реализация разделения настолько проста, но она ломается, когда вы включаете *
(расширяется до содержимого текущего каталога) в качестве элемента и пробела в качестве разделителя:
#!/bin/bash # WARNING: This code has several hidden issues. str="C,Bash,*" arr=(${str//,/ }) echo "${#arr[@]}" # contains current directory content
Изучите современные методы написания сценариев Bash с помощью следующей истории:
Спасибо за прочтение.
Повышение уровня кодирования
Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:
- 👏 Хлопайте за историю и подписывайтесь на автора 👉
- 📰 Смотрите больше контента в публикации Level Up Coding
- 💰 Бесплатный курс собеседования по программированию ⇒ Просмотреть курс
- 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"
🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу