Операции со строками

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

${#параметр}

вернет длину строки, содержащуюся в указанном параметре. Обычно роль параметра играет строка, но если передать @ или *, то механизм подстановки вернет число позиционных параметров.

[me@linuxbox ~]$ foo="This string is long."

[me@linuxbox ~]$ echo "'$foo' is ${#foo} characters long."

'This string is long.' is 20 characters long.

Следующая форма подстановки:

${параметр:смещение}

${параметр:смещение:длина}

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

[me@linuxbox ~]$ foo="This string is long."

[me@linuxbox ~]$ echo ${foo:5}

string is long.

[me@linuxbox ~]$ echo ${foo:5:6}

string

Если указать отрицательное смещение, его отсчет начнется с конца строки вместо начала. Обратите внимание, что отрицательному значению должен предшествовать пробел, чтобы предотвратить путаницу с формой ${параметр:-слово}. Длина, если указана, в этом случае также должна быть меньше 0. Если в качестве параметра передать @, результатом подстановки будет длина позиционных параметров, начиная с указанного смещения.

[me@linuxbox ~]$ foo="This string is long."

[me@linuxbox ~]$ echo ${foo: -5}

long.

[me@linuxbox ~]$ echo ${foo: -5:2}

lo

Следующие две формы:

${параметр#шаблон}

${параметр##шаблон}

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

[me@linuxbox ~]$ foo=file.txt.zip

[me@linuxbox ~]$ echo ${foo#*.}

txt.zip

[me@linuxbox ~]$ echo ${foo##*.}

zip

Следующие две формы:

${параметр%шаблон}

${параметр%%шаблон}

действуют так же, как формы # и ##, представленные выше, но удаляют текст с конца строки, содержащейся в параметре.

[me@linuxbox ~]$ foo=file.txt.zip

[me@linuxbox ~]$ echo ${foo%.*}

file.txt

[me@linuxbox ~]$ echo ${foo%%.*}

file

Следующие формы:

${параметр/шаблон/строка}

${параметр//шаблон/строка}

${параметр/#шаблон/строка}

${параметр/%шаблон/строка}

выполняют поиск с заменой в содержимом указанного параметра. Если в параметре будет найдено совпадение с шаблоном, который может содержать групповые символы, это совпадение будет заменено содержимым указанной строки. Первая форма заменит только первое совпадение с шаблоном. Форма // заменит все найденные совпадения. Форма /# выполняет замену, только если совпадение с шаблоном найдено в самом начале строки, а форма /% выполняет замену, только если совпадение найдено в конце строки. Часть /строка можно опустить, и тогда совпавший фрагмент будет удален.

[me@linuxbox ~]$ foo=JPG.JPG

[me@linuxbox ~]$ echo ${foo/JPG/jpg}

jpg.JPG

[me@linuxbox ~]$ echo ${foo//JPG/jpg}

jpg.jpg

[me@linuxbox ~]$ echo ${foo/#JPG/jpg}

jpg.JPG

[me@linuxbox ~]$ echo ${foo/%JPG/jpg}

JPG.jpg

Механизм подстановки параметров — ценный инструмент. Его возможности для работы со строками можно использовать вместо других широко используемых команд, таких как sed и cut. Применение механизма подстановки способствует увеличению производительности сценария за счет отсутствия необходимости выполнять внешние программы. Например, изменим программу longest-word из предыдущей главы, задействовав подстановку параметра ${#j} взамен подстановки команды $(echo $j | wc -c), которая к тому же выполняется в под­оболочке:

#!/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:

[me@linuxbox ~]$ time longest-word2 dirlist-usr-bin.txt

dirlist-usr-bin.txt: 'scrollkeeper-get-extended-content-list' (38 characters)

real 0m3.618s

user 0m1.544s

sys 0m1.768s

[me@linuxbox ~]$ time longest-word3 dirlist-usr-bin.txt

dirlist-usr-bin.txt: 'scrollkeeper-get-extended-content-list' (38 characters)

real 0m0.060s

user 0m0.056s

sys 0m0.008s

Первоначальной версии потребовалось 3,618 секунды, чтобы просканировать текстовый файл, тогда как новой версии, использующей механизм подстановки параметров, понадобилось всего 0,06 секунды — весьма существенное улучшение.