User Tools

Site Tools


bash:строки_и_числа

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> Целочисленное деление
bash/строки_и_числа.txt · Last modified: 2023/04/06 10:18 (external edit)