9.2. Работа со строками


Bash поддерживает на удивление большое количество операций над строками. К сожалению, этот раздел Bash испытывает недостаток унификации. Одни операции являются подмножеством операций подстановки параметров, а другие — совпадают с функциональностью команды Unix — expr. Это приводит к противоречиям в синтаксисе команд и перекрытию функциональных возможностей, не говоря уже о возникающей путанице.

Длина строки

${#string}
expr length $string
expr "$string" : '.*'
  1. stringZ=abcABC123ABCabc
  2. echo ${#stringZ}                 # 15
  3. echo `expr length $stringZ`      # 15
  4. echo `expr "$stringZ" : '.*'`    # 15


Пример 9-10. Вставка пустых строк между параграфами в текстовом файле

  1. #!/bin/bash
  2. # paragraph-space.sh
  3. # Вставка пустых строк между параграфами в текстовом файле.
  4. # Порядок использования: $0 <FILENAME
  5. MINLEN=45        # Возможно потребуется изменить это значение.
  6. #  Строки, содержащие количество символов меньшее, чем $MINLEN
  7. #+ принимаются за последнюю строку параграфа.
  8. while read line  # Построчное чтение файла от начала до конца...
  9. do
  10.   echo "$line"   # Вывод строки.
  11.   len=${#line}
  12.   if [ "$len" -lt "$MINLEN" ]
  13.     then echo    # Добавление пустой строки после последней строки параграфа.
  14.   fi  
  15. done
  16. exit 0

Длина подстроки в строке (подсчет совпадающих символов ведется с начала строки)

expr match "$string" '$substring'

где $substringрегулярное выражение.

expr "$string" : '$substring'

где $substring — регулярное выражение.

  1. stringZ=abcABC123ABCabc
  2. #       |------|
  3. echo `expr match "$stringZ" 'abc[A-Z]*.2'`   # 8
  4. echo `expr "$stringZ" : 'abc[A-Z]*.2'`       # 8


Index

expr index $string $substring

Номер позиции первого совпадения в $string c первым символом в $substring.

  1. stringZ=abcABC123ABCabc
  2. echo `expr index "$stringZ" C12`             # 6
  3.                                              # позиция символа C.
  4. echo `expr index "$stringZ" 1c`              # 3
  5. # символ 'c' (в #3 позиции) совпал раньше, чем '1'.


Эта функция довольно близка к функции strchr() в языке C.

Извлечение подстроки

${string:position}

Извлекает подстроку из $string, начиная с позиции $position.

Если строка $string"*" или "@", то извлекается позиционный параметр (аргумент), [21] с номером $position.

${string:position:length}

Извлекает $length символов из $string, начиная с позиции $position.

  1. stringZ=abcABC123ABCabc
  2. #       0123456789.....
  3. #       Индексация начинается с 0.
  4. echo ${stringZ:0}                            # abcABC123ABCabc
  5. echo ${stringZ:1}                            # bcABC123ABCabc
  6. echo ${stringZ:7}                            # 23ABCabc
  7. echo ${stringZ:7:3}                          # 23A
  8.                                              # Извлекает 3 символа.
  9. # Возможна ли индексация с "правой" стороны строки?
  10. echo ${stringZ:-4}                           # abcABC123ABCabc
  11. # По-умолчанию выводится полная строка.
  12. # Однако . . .
  13. echo ${stringZ:(-4)}                         # Cabc
  14. echo ${stringZ: -4}                          # Cabc
  15. # Теперь выводится правильно.
  16. # Круглые скобки или дополнительный пробел "экранируют" параметр позиции.
  17. # Спасибо Dan Jacobson, за разъяснения.


Если $string"*" или "@", то извлекается до $length позиционных параметров (аргументов), начиная с $position.

  1. echo ${*:2}          # Вывод 2-го и последующих аргументов.
  2. echo ${@:2}          # То же самое.
  3. echo ${*:2:3}        # Вывод 3-х аргументов, начиная со 2-го.


expr substr $string $position $length

Извлекает $length символов из $string, начиная с позиции $position.

  1. stringZ=abcABC123ABCabc
  2. #       123456789......
  3. #       Индексация начинается с 1.
  4. echo `expr substr $stringZ 1 2`              # ab
  5. echo `expr substr $stringZ 4 3`              # ABC


expr match "$string" '\($substring\)'

Находит и извлекает первое совпадение $substring в $string, где $substring — это регулярное выражение.

expr "$string" : '\($substring\)'

Находит и извлекает первое совпадение $substring в $string, где $substring — это регулярное выражение.

  1. stringZ=abcABC123ABCabc
  2. #       =======
  3. echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'`   # abcABC1
  4. echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'`       # abcABC1
  5. echo `expr "$stringZ" : '\(.......\)'`                   # abcABC1
  6. # Все вышеприведенные операции дают один и тот же результат.


expr match "$string" '.*\($substring\)'

Находит и извлекает первое совпадение $substring в $string, где $substring — это регулярное выражение. Поиск начинается с конца $string.

expr "$string" : '.*\($substring\)'

Находит и извлекает первое совпадение $substring в $string, где $substring — это регулярное выражение. Поиск начинается с конца $string.

  1. stringZ=abcABC123ABCabc
  2. #                ======
  3. echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'`    # ABCabc
  4. echo `expr "$stringZ" : '.*\(......\)'`                       # ABCabc


Удаление части строки

${string#substring}

Удаление самой короткой, из найденых, подстроки $substring в строке $string. Поиск ведется с начала строки

${string##substring}

Удаление самой длинной, из найденых, подстроки $substring в строке $string. Поиск ведется с начала строки

  1. stringZ=abcABC123ABCabc
  2. #       |----|
  3. #       |----------|
  4. echo ${stringZ#a*C}      # 123ABCabc
  5. # Удаление самой короткой подстроки.
  6. echo ${stringZ##a*C}     # abc
  7. # Удаление самой длинной подстроки.


${string%substring}

Удаление самой короткой, из найденых, подстроки $substring в строке $string. Поиск ведется с конца строки

${string%%substring}

Удаление самой длинной, из найденых, подстроки $substring в строке $string. Поиск ведется с конца строки

  1. stringZ=abcABC123ABCabc
  2. #                    ||
  3. #        |------------|
  4. echo ${stringZ%b*c}      # abcABC123ABCa
  5. # Удаляется самое короткое совпадение. Поиск ведется с конца $stringZ.
  6. echo ${stringZ%%b*c}     # a
  7. # Удаляется самое длинное совпадение. Поиск ведется с конца $stringZ.


Пример 9-11. Преобразование графических файлов из одного формата в другой, с изменением имени файла

  1. #!/bin/bash
  2. #  cvt.sh:
  3. #  Преобразование всех файлов в заданном  каталоге,
  4. #+ из графического формата MacPaint, в формат "pbm".
  5. #  Используется утилита "macptopbm", входящая в состав пакета "netpbm",
  6. #+ который сопровождается Brian Henderson (<a href="mailto:bryanh@giraffe-data.com">bryanh@giraffe-data.com</a>).
  7. #  Netpbm — стандартный пакет для большинства дистрибутивов Linux.
  8. OPERATION=macptopbm
  9. SUFFIX=pbm          # Новое расширение файла.
  10. if [ -n "$1" ]
  11. then
  12.   directory=$1      # Если каталог задан в командной строке при вызове сценария
  13. else
  14.   directory=$PWD    # Иначе просматривается текущий каталог.
  15. fi
  16. #  Все файлы в каталоге, имеющие расширение ".mac", считаются файлами
  17. #+ формата  MacPaint.
  18. for file in $directory/* # Подстановка имен файлов.
  19. do
  20.   filename=${file%.*c}   #  Удалить расширение ".mac" из имени файла
  21.                          #+ ( с шаблоном '.*c' совпадают все подстроки
  22.                          #+ начинающиеся с '.' и заканчивающиеся 'c',
  23.   $OPERATION $file > "$filename.$SUFFIX"
  24.                          # Преобразование с перенаправлением в файл с новым именем
  25.   rm -f $file            # Удаление оригинального файла после преобразования.
  26.   echo "$filename.$SUFFIX"  # Вывод на stdout.
  27. done
  28. exit 0
  29. # Упражнение:
  30. # --------
  31. #  Сейчас этот сценарий конвертирует *все* файлы в каталоге
  32. #  Измените его так, чтобы он конвертировал *только* те файлы,
  33. #+ которые имеют расширение ".mac".

Замена подстроки

${string/substring/replacement}

Замещает первое вхождение $substring строкой $replacement.

${string//substring/replacement}

Замещает все вхождения $substring строкой $replacement.

  1. stringZ=abcABC123ABCabc
  2. echo ${stringZ/abc/xyz}           # xyzABC123ABCabc
  3.                                   # Замена первой подстроки 'abc' строкой 'xyz'.
  4. echo ${stringZ//abc/xyz}          # xyzABC123ABCxyz
  5.                                   # Замена всех подстрок 'abc' строкой 'xyz'.


${string/#substring/replacement}

Подстановка строки $replacement вместо $substring, если строка $string начинается найденым соответствием. Поиск ведется с начала строки $string.

${string/%substring/replacement}

Подстановка строки $replacement вместо $substring, если строка $string заканчивается найденым соответствием. Поиск ведется с конца строки $string.

  1. stringZ=abcABC123ABCabc
  2. echo ${stringZ/#abc/XYZ}          # XYZABC123ABCabc
  3.                                   # Поиск ведется с начала строки
  4. echo ${stringZ/%abc/XYZ}          # abcABC123ABCXYZ
  5.                                   # Поиск ведется с конца строки



9.2.1. Использование awk при работе со строками

В качестве альтернативы, Bash-скрипты могут использовать средства awk при работе со строками.

Пример 9-12. Альтернативный способ извлечения подстрок

  1. #!/bin/bash
  2. # substring-extraction.sh
  3. String=23skidoo1
  4. #      012345678    Bash
  5. #      123456789    awk
  6. # Обратите внимание на различия в индексации:
  7. # Bash начинает индексацию с '0'.
  8. # Awk  начинает индексацию с '1'.
  9. echo ${String:2:4} # с 3 позиции (0-1-2), 4 символа
  10.                    # skid
  11. # В эквивалент в awk: substr(string,pos,length).
  12. echo | awk '
  13. { print substr("'"${String}"'",3,4)      # skid
  14. }
  15. '
  16. #  Передача пустого "echo" по каналу в awk, означает фиктивный ввод,
  17. #+ делая, тем самым, ненужным предоставление имени файла.
  18. exit 0

9.2.2. Дальнейшее обсуждение

Дополнительную информацию, по работе со строками, вы найдете в разделе Section 9.3 и в секции, посвященной команде expr. Примеры сценариев:

  1. Пример 12-9

  2. Пример 9-15

  3. Пример 9-16

  4. Пример 9-17

  5. Пример 9-19


[21]    Применяется к аргументам командной строки или входным параметрам функций.