Table of Contents
bash Строки и числа
Любые компьютерные программы обрабатывают данные. В предыдущих статьях основное внимание уделялось обработке данных на уровне файлов. Однако многие задачи решаются с использованием меньших единиц данных, таких как строки и числа.
В этой главе мы рассмотрим некоторые возможности командной оболочки для работы со строками и числами. Командная оболочка поддерживает большое разнообразие способов подстановки параметров, которые выполняют строковые операции. В дополнение к подстановке результатов арифметических выражений (о которой рассказывалось в статье – Подстановка) существует программа командной строки bc, выполняющая математические операции.
Подстановка параметров
О механизме подстановки параметров уже рассматривался в статье – Подстановка), но там этот механизм не был описан детально, потому что большая часть его возможностей используется в сценариях, а не в командной строке. Мы уже знакомы с некоторыми формами подстановки параметров, например, с подстановкой значений переменных командной оболочки. Но в командной оболочке их намного больше.
<callout type=“primary” icon=“true” title=“Примечание”>Старайтесь всегда заключать операции подстановки параметров в двойные кавычки, чтобы предотвратить нежелательное разделение строк на слова, если для этого нет веских причин. Это особенно актуально при работе с именами файлов, потому что они могут включать пробелы и другие неожиданные символы.</callout>
Простые параметры
Простейшую форму подстановки параметров можно наблюдать в использовании переменных. Например, запись
$a
после подстановки превращается в содержимое переменной a. Простые параметры можно заключать в фигурные скобки, например:
${a}
Это не оказывает влияния на результат подстановки, но является необходимым, если сразу за именем переменной следует какой-то другой текст, который может сбивать с толку командную оболочку. В следующем примере выполняется попытка сконструировать имя файла добавлением строки _file к содержимому переменной a:
a="foo" echo "$a_file"
Если выполнить эту последовательность команд, результатом будет пустое значение, потому что командная оболочка попытается выполнить подстановку значения переменной a_file вместо a. Эта проблема устраняется с помощью фигурных скобок:
echo "${a}_file" foo_file
Мы видели также (смотрите статью – Позиционные параметры), что доступ к позиционным параметрам с порядковыми номерами выше 9 тоже осуществляется с помощью фигурных скобок. Например, прочитать 11-й позиционный параметр можно следующим образом:
${11}
Подстановка пустых переменных
Некоторые формы подстановки параметров помогают решать проблемы с несуществующими, или пустыми, переменными. Эти формы удобно использовать для обработки ситуаций отсутствия позиционных параметров и назначения им значений по умолчанию. Ниже приводится пример такой подстановки:
${параметр:-слово}
Если параметр не определен (то есть отсутствует) или содержит пустое значение, механизм подстановки вернет значение указанного слова. Если параметр не пустой, механизм подстановки вернет значение параметра.
foo= echo ${foo:-"substitute value if unset"} substitute value if unset echo $foo foo=bar echo ${foo:-"substitute value if unset"} bar echo $foo bar
Вот еще один вариант подстановки, где вместо дефиса используется знак «равно»:
foo= echo ${foo:="default value if unset"} default value if unset echo $foo default value if unset foo=bar echo ${foo:="default value if unset"} bar echo $foo bar
<callout type=“primary” icon=“true” title=“Примечание”>Таким способом нельзя присваивать значения позиционным и другим специальным параметр</callout> Ниже демонстрируется форма со знаком вопроса:
${параметр:?слово}
Если параметр не определен или содержит пустое значение, механизм подстановки завершит сценарий с ошибкой и выведет значение указанного слова в стандартный вывод ошибок. Если параметр не пустой, механизм подстановки вернет значение параметра.
foo= echo ${foo:?"default value if unset"} -bash: foo: default value if unset echo $? 1 foo=bar cho ${foo:?"default value if unset"} bar echo $? 0
Ниже демонстрируется форма со знаком «плюс»:
${параметр:+слово}
Если параметр не определен или содержит пустое значение, механизм подстановки вернет пустое значение. Если параметр не пустой, механизм подстановки вернет значение слова, но сам параметр не изменится.
foo= echo ${foo:+"default value if unset"} foo=bar echo ${foo:+"default value if unset"} default value if unset
Получение имен переменных
Командная оболочка может возвращать имена переменных. Это используется в некоторых экзотических ситуациях.
${!префикс*} ${!префикс@}
Эти две формы подстановки возвращают имена существующих переменных, начинающиеся с указанного префикса. Согласно документации bash, обе формы действуют совершенно одинаково. Следующая команда выводит список всех переменных окружения с именами, начинающимися с BASH:
echo ${!BASH*} BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_ARGV0 BASH_CMDS BASH_COMMAND BASH_COMPLETION_VERSINFO BASH_LINENO BASH_REMATCH BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION
Операции со строками
Существует множество форм подстановки, которые можно использовать для работы со строками. Многие из них особенно хорошо подходят для операций с путями. Форма
${#параметр}
вернет длину строки, содержащуюся в указанном параметре. Обычно роль параметра играет строка, но если передать <html>@</html> или <html>*</html>, то механизм подстановки вернет число позиционных параметров.
foo="This string is long." echo "'$foo' is ${#foo} characters long." 'This string is long.' is 20 characters long.
Следующая форма подстановки
${параметр:смещение} ${параметр:смещение:длина}
используется для извлечения фрагмента строки, содержащейся в параметре. Извлечение начинается с указанного смещения от начала строки и продолжается до конца строки, если не указана длина.
foo="This string is long." echo ${foo:5} string is long. echo ${foo:5:6} string
Если указать отрицательное смещение, его отсчет начнется с конца строки вместо начала. Обратите внимание, что отрицательному значению должен предшествовать пробел, чтобы предотвратить путаницу с формой <html>${параметр:-слово}</html>. Длина, если указана, в этом случае не должна быть меньше 0.
Если в качестве параметра передать <html>@</html>, результатом подстановки будет длина позиционных параметров, начиная с указанного смещения.
foo="This string is long." echo ${foo: -5} long. echo ${foo: -5:2} lo
Следующие две формы
${параметр#шаблон} ${параметр##шаблон}
возвращают значение параметра, удаляя из него начальную часть, определяемую указанным шаблоном.
В шаблоне допускается использовать групповые символы: например, те, что используются в подстановке путей. Эти две формы отличаются тем, что форма <html>#</html> удаляет кратчайшее совпадение, тогда как форма <html>##</html> удаляет самое длинное совпадение.
foo=file.txt.zip echo ${foo#*.} txt.zip echo ${foo##*.} zip
Следующие две формы
${параметр%шаблон} ${параметр%%шаблон}
действуют так же, как формы <html>#</html> и <html>##</html>, представленные выше, но удаляют текст с конца строки, содержащейся в параметре.
foo=file.txt.zip echo ${foo%.*} file.txt echo ${foo%%.*} file
Следующие формы
${параметр/шаблон/строка} ${параметр//шаблон/строка} ${параметр/#шаблон/строка} ${параметр/%шаблон/строка}
выполняют поиск с заменой в содержимом указанного параметра. Если в параметре будет найдено совпадение с шаблоном, который может содержать групповые символы, это совпадение будет заменено содержимым указанной строки. Первая форма заменит только первое совпадение с шаблоном. Форма <html></html> заменит все найденные совпадения. Форма <html>/#</html> выполняет замену, только если совпадение с шаблоном найдено в самом начале строки, а форма <html>/%</html> выполняет замену, только если совпадение найдено в конце строки. Часть <html>/строка</html> можно опустить, и тогда совпавший фрагмент будет удален. <code bash>foo=JPG.JPG echo ${foo/JPG/jpg} jpg.JPG echo ${fooJPG/jpg} jpg.jpg
echo ${foo/#JPG/jpg} jpg.JPG
echo ${foo/%JPG/jpg} JPG.jpg</code> Механизм подстановки параметров – ценный инструмент. Его возможности для работы со строками можно использовать вместо других широко используемых команд, таких как sed и cut. Применение механизма подстановки способствует увеличению производительности сценария за счет отсутствия необходимости выполнять внешние программы. Например, изменим программу longest-word из статьи Цикл for, задействовав подстановку параметра <html>${#j}</html> взамен подстановки команды <html>$(echo $j | wc -c)</html>, которая к тому же выполняется в подоболочке:
#!/bin/bash # longest-word3 : поиск самой длинной строки в файле for i; do if [[ -r "$i" ]]; then max_word= max_len= for j in $(strings $i); do len="${#j}" if (( len > max_len )); then max_len="$len" max_word="$j" fi done echo "$i: '$max_word' ($max_len characters)" fi shift done
Далее, сравним эффективность двух версий с помощью команды time:
time longest_word2 distros.txt distros.txt: '12/07/2006' (11 characters) real 0m0.046s user 0m0.053s sys 0m0.010s time longest_word3 distros.txt distros.txt: '12/07/2006' (10 characters) real 0m0.003s user 0m0.003s sys 0m0.000s
Первоначальной версии потребовалось 0.046 секунды, чтобы просканировать текстовый файл, тогда как новой версии, использующей механизм подстановки параметров, понадобилось всего 0,003 секунды – весьма существенное улучшение.
Преобразование регистра символов
bash поддерживает четыре подстановки параметров и два варианта команды declare для преобразования регистра символов в строках.
Где может пригодиться возможность преобразования регистра символов? Помимо очевидной эстетической ценности, она играет важную роль в программировании. Рассмотрим случай поиска в базе данных. Представьте, что пользователь ввел строку и мы должны найти ее в базе данных. Пользователь может ввести значение только заглавными или только строчными буквами или их комбинацией. Разумеется, мы не можем позволить себе хранить в базе данных все возможные варианты написания всех строк с заглавными и строчными буквами. Как же быть?
Подобные проблемы часто решаются путем нормализации пользовательского ввода. То есть его преобразованием в стандартную форму перед поиском в базе данных. Для этого можно преобразовать все символы во вводе пользователя в нижний или верхний регистр и аналогичным образом нормализовать все записи в базе данных.
Для нормализации строк — приведения их к верхнему или нижнему регистру – можно использовать команду declare. C помощью declare мы сможем гарантировать, что переменная всегда будет содержать строки в желаемом формате, независимо от их первоначального вида.
#!/bin/bash # ul-declare: демонстрация преобразования регистра символов с использованием declare declare -u upper declare -l lower if [[ $1 ]]; then upper="$1" lower="$1" echo "$upper" echo "$lower" fi
В предыдущем сценарии мы использовали declare для создания двух переменных, upper и lower. Затем мы присвоили им значение первого аргумента командной строки (позиционного параметра $1) и вывели их на экран.
ul-declare aBc ABC abc
Как видите, аргумент командной строки (aBc) был нормализован.
Кроме команды declare поддерживаются также четыре подстановки параметров, выполняющие преобразование символов в верхний/нижний регистр. Они перечислены в таблице ниже.
Формат | Результат | ||
---|---|---|---|
<html>${параметр,,шаблон}</html> | Возвращает значение указанного параметра после преобразования всех символов в нижний регистр. Необязательный шаблон можно использовать для ограничения символов, подлежащих преобразованию (например [A-F]). Подробное описание шаблонов можно найти в странице справочного руководства (man) для команды bash | ||
<html>${параметр,,шаблон}</html> | Возвращает значение указанного параметра после преобразования в нижний регистр только первого символа | ||
<html>${параметр | шаблон}</html> | Возвращает значение указанного параметра после преобразования всех символов в верхний регистр | |
<html>${параметр | шаблон}</html> | Возвращает значение указанного параметра после преобразования в верхний регистр только первого символа |
Работу этих операций подстановки демонстрирует следующий сценарий:
#!/bin/bash # ul-param: демонстрация преобразования регистра символов # с использованием подстановки параметров if [[ "$1" ]]; then echo "${1,,}" echo "${1,}" echo "${1^^}" echo "${1^}" fi
Результат выполнения этого сценария:
ul-param aBc abc aBc ABC ABc
Здесь мы снова обрабатываем первый аргумент командной строки и выводим результаты выполнения четырех поддерживаемых вариантов подстановки параметров. Сценарий использует первый позиционный параметр, но вообще в операцию подстановки можно передать любую строку, переменную или строковое выражение.
Вычисление и подстановка арифметических выражений
В статье Подстановка мы видели, как работает механизм подстановки результатов арифметических выражений. Он используется для выполнения разных арифметических операций с целыми числами. Ниже приводится его базовый синтаксис
$((выражение))
где выражение – это любое допустимое арифметическое выражение.
Этот вид подстановки тесно связан с составной командой <html>1)</html>, использовавшейся в статье – Управление потоком выполнения, для вычисления арифметических выражений (оценки истинности).
В предыдущих статьях мы видели некоторые наиболее типичные выражения и операторы, а здесь рассмотрим более полный их список.
Основание системы счисления
В статье Привилегии мы познакомились с восьмеричными (в системе счисления с основанием 8) и шестнадцатеричными (в системе счисления с основанием 16) числами. В арифметических выражениях командная оболочка позволяет использовать целочисленные константы в системах счисления с любым основанием. В следующей таблице показаны формы записи чисел с указанием основания системы счисления.
Форма записи | Описание |
---|---|
<html>Число</html> | По умолчанию числа без упоминания системы счисления интерпретируются как десятичные числа (в системе счисления с основанием 10) |
<html>0число</html> | В арифметических выражениях числа, начинающиеся с нуля, интерпретируются как восьмеричные (в системе счисления с основанием 8) |
<html>0хчисло</html> | Форма записи шестнадцатеричных чисел |
<html>основание#число</html> | Число в системе счисления с указанным основанием |
Несколько примеров:
echo $((0xff)) 255 echo $((2#11111111)) 255
В этих примерах выводится значение шестнадцатеричного числа ff (наибольшее двухзначное число) и наибольшее восьмизначное двоичное число (в системе счисления с основанием 2).
Унарные операторы
Оболочка поддерживает два унарных оператора, <html>+</html> и <html>-</html>, используемых для обозначения положительных и отрицательных чисел соответственно.
Простая арифметика
В таблице перечислены обычные арифметические операторы.
Оператор | Описание |
---|---|
<html>+</html> | Сложение |
<html>-</html> | Вычитание |
<html>*</html> | Умножение |
<html>/</html> | Целочисленное деление |