#!/bin/bash
# basics-reviewed.bash
# Расширение файла == *.bash == сценарий, использующий особенности Bash
# Copyright (c) Michael S. Zick, 2003; All rights reserved.
# License: Use in any form, for any purpose.
# Издание: $ID$
#
# Правка, с целью улучшения оформления, выполнена автором книги.
# ("Advanced Bash Scripting Guide")
# Этот сценарий тестировался в Bash версий 2.04, 2.05a и 2.05b.
# Он может не работать в более ранних версиях.
# Этот сценарий умышленно генерирует ошибку
#+ "command not found". См. строку 394.
# Ведущий разработчик Bash, Chet Ramey, обязался исправить эту проблему
#+ в следующих версиях Bash.
###-------------------------------------------###
### Сценарий выводит много информации на ###
###+ экран, поэтому запускайте его в конвейере###
###+ с командой more ###
### ###
### Кроме того, вы можете перенаправить ###
###+ вывод в файл, с целью последующего ###
###+ изучения ###
###-------------------------------------------###
# Большая часть из приводимых здесь моментов описывается
#+ в вышеупомянутой книге "Advanced Bash Scripting Guide."
# Этот сценарий, по сути можно расценивать как своего рода презентацию.
# — msz
# Переменные не типизированы, если не указано обратное.
# Соглашения по именованию переменных.
# Имена переменных не должны начинаться с цифровых символов.
# Имена дескрипторов файлов (как например: 2>&1)
#+ должны содержать ТОЛЬКО цифры.
# Параметры и элементы массивов Bash — пронумерованы.
# (Параметры, в этом смысле, очень похожи на массивы.)
# Переменные в Bash могут иметь неопределенное значение.
unset VarNull
# Переменные в Bash могут быть опеределены, но содержать "пустое" (null) значение.
VarEmpty=''
# Переменные могут быть определены и содержать некоторое, непустое значение
VarSomething='Literal'
# Переменные могут хранить:
# * Целое 32-битовое число со знаком
# * Строку символов
# Переменные могут быть массивом.
# Строки могут содержать пробелы и интерпретироваться
#+ как вызов функции с аргументами.
# Имена переменных и имена функций
#+ находятся в разных пространствах имен (namespaces).
# Переменные могут быть объявлены массивами как явно, так и неявно
#+ в зависимости от семантики операции присваивания.
# Явно:
declare -a ArrayVar
# Команда echo — внутренняя команда.
echo $VarSomething
# Команда printf — внутренняя команда.
# здесь %s интерпретируется как строка формата
printf %s $VarSomething # Перевод строки отсутствует, ничего не выводится.
echo # Выводит только перевод строки.
# Интерпретатор Bash различает отдельные слова по символу пробела между ними.
# Поэтому наличие или отсутствие пробела — очень важный признак.
# (В общем случае это так, но есть и исключения из правил.)
# Символ "доллара" ($) интерпретируется как: Content-Of (содержимое для ...).
# Расширенный синтаксис, с использованием символа "доллара":
echo ${VarSomething}
# Здесь, конструкция ${ ... }, позволяет указывать
#+ не только имена переменных.
# Как правило, запись $VarSomething
#+ всегда может быть представлена в виде : ${VarSomething}.
# Чтобы увидеть следующие операции в действии — вызовите сценарий
#+ с несколькими входными аргументами.
# За пределами двойных кавычек, специальные символы @ и *
#+ имеют идентичное назначение.
# Может произноситься как: All-Elements-Of (Все-Элементы-Для).
# Если имя переменной не указано, то эти специальные символы
#+ применяются к предопределенным переменным Bash.
echo $* # Все входные параметры сценария или функции
echo ${*} # То же самое
# Bash запрещает подстановку имен файлов в вышеупомянутых конструкциях.
# Ссылка на Все-Элементы-Для
echo $@ # то же самое, что и выше
echo ${@} # то же самое
# Внутри двойных кавычек, поведение символов @ и *
#+ зависит от установки переменной IFS (Input Field Separator — Разделитель Полей).
# Ссылка на Все-Элементы-Для, внутри двойных кавычек, работает точно так же.
# Обращение к имени переменной означает получение
#+ всех элементов (символов) строки.
# Для обращения к отдельным элементам (символам) строки,
#+ может использоваться расширенный синтаксис (см. ниже).
# Обращение к имени переменной-массива в Bash
#+ означает обращение к нулевому элементу массива,
#+ а НЕ к ПЕРВОМУ ОПРЕДЕЛЕННОМУ или к ПЕРВОМУ ИНИЦИАЛИЗИРОВАННОМУ элементу.
# Для обращения к другим элементам массива, необходимо явное указание элемента,
#+ это означает, что ДОЛЖЕН использоваться расширенный синтаксис.
# В общем случае: ${name[subscript]}.
# Для строк может использоваться такая форма записи: ${name:subscript},
#+ а также для обращения к нулевому элементу массива.
# Массивы в Bash реализованы как связанные списки,
#+ а не как фиксированная область памяти, что характерно для некоторых
#+ языков программирования.
# Характеристики массивов в Bash:
# -------------------------------
# Если не определено иначе, индексация массивов в Bash
#+ начинается с нуля: [0]
# Это называется "индексация с нуля".
###
# Если не указано иначе, массивы в Bash являются упакованными
#+ (т.е. массивы просто не содержат элементов с отсутствующими индексами).
###
# Отрицательные индексы недопустимы.
###
# Элементы массива не обязательно должны быть одного и того же типа.
###
# Элементы массива могут быть неинициализированы.
# Т.е. массив может быть "разреженным"
###
# Элементы массива могут быть инициализированы пустым значением.
###
# Элементы массива могут содержать:
# * Целое 32-битовое число со знаком
# * Строку
# * Форматированную строку, которая выглядит
# + как вызов к функции с параметрами
###
# Инициализированные элементы массива могут быть деинициализированы (unset).
# Т.е. массив может быть переупакован так,
# + что он не будет содержать элемента с данным индексом.
###
# К массиву могут добавляться дополнительные элементы,
#+ не определенные ранее.
###
# По этим причинам я называю массивы Bash — "Bash-массивами" ("Bash-Arrays").
#
# — msz
# Демонстрация вышесказанного — инициализируем ранее объявленный массив ArrayVar
#+ как "разреженный" массив.
# (команда 'unset ... ' используется для демонстрации вышесказанного.)
unset ArrayVar[0] # Для демонстрации
ArrayVar[1]=one # Без кавычек
ArrayVar[2]='' # Инициализация пустым значением
unset ArrayVar[3] # Для демонстрации
ArrayVar[4]='four' # В кавычках
# Строка формата %q — трактуется как: Quoted-Respecting-IFS-Rules
#+ (в соответствии с установками IFS).
echo
echo '- - Вне двойных кавычек - -'
###
printf %q ${ArrayVar[*]} # Шаблон "Все-Элементы-Для"
echo
echo 'команда echo:'${ArrayVar[*]}
###
printf %q ${ArrayVar[@]} # "Все-Элементы-Для"
echo
echo 'команда echo:'${ArrayVar[@]}
# Двойные кавычки используются для разрешения операции подстановки
#+ внутри кавычек.
# Существует пять самых распространенных случаев,
#+ зависящих от установок переменной IFS.
echo
echo '- - В двойных кавычках - По-умолчанию IFS содержит пробел-табуляцию-перевод строки- -'
IFS=$'\x20'$'\x09'$'\x0A' # Три байта,
#+ и именно в таком порядке.
printf %q "${ArrayVar[*]}" # Шаблон "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[*]}"
###
printf %q "${ArrayVar[@]}" # "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[@]}"
echo
echo '- - В двойных кавычках - Первый символ в IFS: ^ - -'
# Любой печатаемый, непробельный символ, дает тот же эффект.
IFS='^'$IFS # ^ + пробел табуляция перевод строки
###
printf %q "${ArrayVar[*]}" # Шаблон "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[*]}"
###
printf %q "${ArrayVar[@]}" # "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[@]}"
echo
echo '- - В двойных кавычках - IFS не содержит пробела - -'
IFS='^:%!'
###
printf %q "${ArrayVar[*]}" # Шаблон "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[*]}"
###
printf %q "${ArrayVar[@]}" # "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[@]}"
echo
echo '- - В двойных кавычках - переменная IFS пуста - -'
IFS=''
###
printf %q "${ArrayVar[*]}" # Шаблон "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[*]}"
###
printf %q "${ArrayVar[@]}" # "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[@]}"
echo
echo '- - В двойных кавычках - переменная IFS не определена - -'
unset IFS
###
printf %q "${ArrayVar[*]}" # Шаблон "Все-Элементы-Для" All-Elements-Of
echo
echo 'команда echo:'"${ArrayVar[*]}"
###
printf %q "${ArrayVar[@]}" # "Все-Элементы-Для"
echo
echo 'команда echo:'"${ArrayVar[@]}"
# Вернем переменную IFS в первоначальное состояние,
# записав в нее значение по-умолчанию.
IFS=$'\x20'$'\x09'$'\x0A' # точно в таком порядке.
# Интерпретация результатов, полученных выше:
# Форма ввыода по шаблону "Все-Элементы-Для" зависит от содержимого переменной IFS.
###
# Простой вывод "Всех-Элементов-Для" не зависит от содержимого переменной IFS.
###
# Обратите внимание на различия, имеющиеся в выводе
#+ от команд echo и printf с форматом %q.
# Давайте вспомним:
# Параметры очень похожи на массивы и имеют сходное поведение.
###
# Примеры выше показывают, что для того, чтобы вывести разреженный
#+ массив полностью, необходимо писать дополнительный код.
###
# Длина строки равна количеству ненулевых элементов (символов):
echo
echo '- - Имя переменной употребляется вне кавычек - -'
echo 'Количество ненулевых символов: '${#VarSomething}'.'
# test='Lit'$'\x00''eral' # $'\x00' — нулевой (null) символ.
# echo ${#test} # Что получится?
# Длина массива равна количеству инициализированных элементов,
#+ включая элементы, инициализированные пустыми значениями.
echo
echo 'Количество инициализированных элементов в массиве: '${#ArrayVar[@]}'.'
# Это НЕ максимальный индекс массива (4).
# Это НЕ ширина диапазона (1 . . 4 включительно).
# Это длина связного списка.
###
# Максимальный номер индекса массива и диапазон индексов
#+ могут быть найдены, но для этого потребуется дополнительный код.
# Длина строки равна количеству ненулевых элементов (символов):
echo
echo '- - Имя переменной употребляется в кавычках - -'
echo 'Количество непустых символов: '"${#VarSomething}"'.'
# Длина массива равна количеству инициализированных элементов,
#+ включая элементы, инициализированные пустыми значениями.
echo
echo 'Количество инициализированных элементов в массиве: '"${#ArrayVar[*]}"'.'
# Вывод: Конструкция ${# ... } не производит подстановку.
# Совет:
# Всегда используйте символ All-Elements-Of (Все-Элементы-Для)
#+ если желаете получить результат, не зависящий от содержимого переменной IFS.
# Определим простую функцию.
# Я включил в имя функции символ подчеркивания
#+ чтобы как-то обозначить, что это функция, а не переменная.
###
# Bash различает имена функций и переменных,
#+ размещая из в различных пространствах имен.
###
_simple() {
echo -n 'SimpleFunc'$@ # Символ перевода строки в любом случае
} #+ будет "съеден".
# Конструкция ( ... ) вызывает команду или функцию.
# Форма записи $( ... ) произносится как: Result-Of (Результат-Выполнения).
# Вызовем функцию _simple
echo
echo '- - Результат работы функции _simple - -'
_simple # Попробуйте передать несколько аргументов.
echo
# или
(_simple) # Попробуйте передать несколько аргументов.
echo
echo '- Существует ли переменная с таким именем? -'
echo $_simple not defined # Нет переменной с таким именем.
# Обращение к результату выполнения функции _simple
# (будет получено сообщение об ошибке)
###
$(_simple) # Генерирует сообщение об ошибке:
# line 394: SimpleFunc: command not found
# ---------------------------------------
echo
###
# Причина ошибки вполне очевидна: результат работы функции _simple не есть
#+ ни команда Bash, ни имя определенной ранее функции.
###
# Этот пример показывает, что вывод от функции _simple подвергается
#+ дополнительной интерпретации.
###
# Вывод:
# Функция может использоваться для генерации команд Bash.
# Простая функция, которая выводит команду bash:
###
_print() {
echo -n 'printf %q '$@
}
echo '- - Результат работы функции _print - -'
_print parm1 parm2 # Простой вывод — НЕ команда.
echo
$(_print parm1 parm2) # Исполняет команду printf %q parm1 parm2
# См. пример с IFS выше
#+ на предмет дополнительных возможнойстей.
echo
$(_print $VarSomething) # Вполне предсказуемый результат.
echo
# Переменные-функции
# ------------------
echo
echo '- - Переменные-функции - -'
# Переменная может хранить целое число, строку или массив.
# Строка может интерпретироваться как вызов функции.
# set -vx # Раскомментарьте при желании
declare -f funcVar # в пространстве имен функций!
funcVar=_print # Записать имя функции.
$funcVar parm1 # Аналогично вызову функции _print.
echo
funcVar=$(_print ) # Результат работы функции.
$funcVar # Нет ни ввода, ни вывода.
$funcVar $VarSomething # Предсказуемый результат.
echo
funcVar=$(_print $VarSomething) # Здесь выполняется подстановка
#+ значения переменной $VarSomething.
$funcVar # Содержимое переменной $VarSomething
echo #+ стало частью переменной $funcVar
funcVar="$(_print $VarSomething)" # Здесь выполняется подстановка
#+ значения переменной $VarSomething.
$funcVar # Содержимое переменной $VarSomething
echo #+ стало частью переменной $funcVar
# Различия в применении или неприменении двойных кавычек
#+ объясняются в примере "protect_literal.sh".
# В первом случае Bash обрабатывает строку как два отдельных слова,
# во втором — как одно слово в кавычках с пробелом внутри слова.
# Отложенная подстановка
# ----------------------
echo
echo '- - Отложенная подстановка - -'
funcVar="$(_print '$VarSomething')" # Подстановка значения переменной не производится.
eval $funcVar # Подстановка производится ЗДЕСЬ.
echo
VarSomething='NewThing'
eval $funcVar # Подстановка производится ЗДЕСЬ.
echo
# Восстановим прежнее значение переменной VarSomething.
VarSomething=Literal
# В примерах "protect_literal.sh" и "unprotect_literal.sh"
#+ вы найдете две функции, которые выполняют отложенную подстановку
#+ значений переменных.
# ОБЗОР:
# -----
# Строки могут рассматриваться как классический массив элементов-символов.
# Строковые операции воздействуют на все элементы (символы) строки
###
# Запись: ${array_name[@]} представляет все элементы
#+ Bash-Массива: array_name.
###
# Строковые операции, в расширенном синтаксисе, могут манипулировать
#+ всеми элементами массива сразу.
###
# Эта способность может рассматриваться как операция For-Each над вектором строк.
###
# Параметры подобны массивам.
# Различия в параметрах для функции и сценария касаются только параметра
#+ ${0}, который никогда не изменяется.
###
# Нулевой параметр сценария содержит имя файла сценария
###
# Нулевой параметр функции НЕ СОДЕРЖИТ имени функции.
# Имя функции хранится в служебной переменной $FUNCNAME.
###
echo
echo '- - Тест (без изменения содержимого переменной) - -'
echo '- неинициализированная переменная -'
echo -n ${VarNull-'NotSet'}' ' # NotSet
echo ${VarNull} # только перевод строки
echo -n ${VarNull:-'NotSet'}' ' # NotSet
echo ${VarNull} # только перевод строки
echo '- "пустая" переменная -'
echo -n ${VarEmpty-'Empty'}' ' # только пробел
echo ${VarEmpty} # только перевод строки
echo -n ${VarEmpty:-'Empty'}' ' # Empty
echo ${VarEmpty} # только перевод строки
echo '- непустая переменная -'
echo ${VarSomething-'Content'} # Literal
echo ${VarSomething:-'Content'} # Literal
echo '- Разреженный массив -'
echo ${ArrayVar[@]-'not set'}
# ASCII-Art time
# State Y==yes, N==no
# - :-
# Unset Y Y ${# ... } == 0
# Empty N Y ${# ... } == 0
# Contents N N ${# ... } > 0
# Либо первая, либо вторая часть операции подстановки параметра по-умолчанию
#+ может быть командой или вызовом функции.
echo
echo '- - Тест 1, не определенная переменная - -'
declare -i t
_decT() {
t=$t-1
}
# Для не определенной переменной: t == -1
t=${#VarNull} # t == 0
${VarNull- _decT } # Вызов функции, теперь t == -1.
echo $t
# "Пустая" переменная: t == 0
t=${#VarEmpty} # t == 0
${VarEmpty- _decT } # Функция _decT НЕ вызывается.
echo $t
# Непустая переменная: t == число непустых символов
VarSomething='_simple' # Записать имя функции в переменную.
t=${#VarSomething} # ненулевая длина
${VarSomething- _decT } # Вызывается функция _simple.
echo $t # Обратите внимание на вывод.
# Упражнение: Разберитесь в этом примере.
unset t
unset _decT
VarSomething=Literal
echo
echo '- - Тест (с изменением содержимого переменной) - -'
echo '- Присвоить, если переменная не определена -'
echo -n ${VarNull='NotSet'}' ' # NotSet NotSet
echo ${VarNull}
unset VarNull
echo '- Присвоить, если переменная не определена -'
echo -n ${VarNull:='NotSet'}' ' # NotSet NotSet
echo ${VarNull}
unset VarNull
echo '- Не присваивать, если переменная пуста -'
echo -n ${VarEmpty='Empty'}' ' # только пробел
echo ${VarEmpty}
VarEmpty=''
echo '- Присвоить, если переменная пуста -'
echo -n ${VarEmpty:='Empty'}' ' # Empty Empty
echo ${VarEmpty}
VarEmpty=''
echo '- Не изменять, если переменная не пуста -'
echo ${VarSomething='Content'} # Literal
echo ${VarSomething:='Content'} # Literal
# "Разреженные" Bash-Массивы
###
# Bash-Массивы не содержат пустых элементов, и индексация их,
#+ если не оговорено иное, начинается с нуля.
###
# Инициализируем массив ArraySparse как раз тем способом,
#+ когда "оговорено иное". Ниже приведен один из вариантов:
###
echo
declare -a ArraySparse
ArraySparse=( [1]=one [2]='' [4]='four' )
# [0]=нет элемента, [2]=пустой элемент, [3]=нет элемента
echo '- - Разреженный массив - -'
# В двойных кавычках, значение IFS — по-умолчанию, Все-Элементы-Для
IFS=$'\x20'$'\x09'$'\x0A'
printf %q "${ArraySparse[*]}"
echo
# Обратите внимание на отсутствие различий в том, как выводятся отсутствующий
#+ и пустой элементы массива.
# Оба выводятся как экранированные пробелы.
###
# Не упустите из виду и то, что все неопределенные элементы массива,
#+ предшествующие первому инициализированному элементу, не выводятся
###
# Замечание о таком "поведении" Bash, версий 2.04, 2.05a и 2.05b,
#+ было передано разработчикам has been reported
#+ и возможно будет изменено в последующих версиях Bash.
# Чтобы вывести содержимое такого разреженного массива без изменений
#+ требуется некоторое количество усилий.
# Вот один из возможных вариантов вывода такого массива:
###
# local l=${#ArraySparse[@]} # Количество инициализированных элементов
# local f=0 # Количество найденных индексов
# local i=0 # текущий индекс
( # Анонимная функция
for (( l=${#ArraySparse[@]}, f = 0, i = 0 ; f < l ; i++ ))
do
# 'if defined then...'
${ArraySparse[$i]+ eval echo '\ ['$i']='${ArraySparse[$i]} ; (( f++ )) }
done
)
# Важно:
# Команда "read -a array_name" начинает заполнять массив
#+ array_name с нулевого элемента.
# ArraySparse — не содержит нулевого элемента.
###
# Для выполнения операций над разреженными массивами,
#+ такими как чтение/запись массива из/в файла
#+ программист должен сам создать программный код, который
#+ будет удовлетворять его потребности.
###
# Упражнение: разберитесь в следующем примере самостоятельно.
unset ArraySparse
echo
echo '- - Замена по условию (замена не производится)- -'
echo '- Не изменять если переменная не определена -'
echo -n ${VarNull+'NotSet'}' '
echo ${VarNull}
unset VarNull
echo '- Не изменять если переменная не определена -'
echo -n ${VarNull:+'NotSet'}' '
echo ${VarNull}
unset VarNull
echo '- Изменить если переменная пуста -'
echo -n ${VarEmpty+'Empty'}' ' # Empty
echo ${VarEmpty}
VarEmpty=''
echo '- Не изменять если переменная пуста -'
echo -n ${VarEmpty:+'Empty'}' ' # Только пробел
echo ${VarEmpty}
VarEmpty=''
echo '- Изменить, если переменная не пуста -'
echo -n ${VarSomething+'Content'}' ' # Content Literal
echo ${VarSomething}
# Вызов функции
echo -n ${VarSomething:+ $(_simple) }' ' # SimpleFunc Literal
echo ${VarSomething}
echo
echo '- - Разреженный массив - -'
echo ${ArrayVar[@]+'Empty'} # An array of 'Empty'(ies)
echo
echo '- - Тест 2, неопределенные переменные - -'
declare -i t
_incT() {
t=$t+1
}
# Обратите внимание:
# Тот же самый тест, что и в случае с разреженными массивами
# Неопределенная переменная: t == -1
t=${#VarNull}-1 # t == -1
${VarNull+ _incT } # Функция не вызывается.
echo $t' Переменная не определена'
# Пустая переменная: t == 0
t=${#VarEmpty}-1 # t == -1
${VarEmpty+ _incT } # Вызов функции.
echo $t' Переменная пуста'
# Переменная не пуста: t == (количество непустых символов)
t=${#VarSomething}-1 # количество_непустых_символов минус один
${VarSomething+ _incT } # Вызов функции.
echo $t' Переменная не пуста'
# Операции над элементами массива
# -------------------------------
echo
echo '- - Выборка элементов - -'
# Строки, массивы и позиционные параметры
# Чтобы увидеть работу сценария с позиционными параметрами,
#+ вызовите его с несколькими аргументами
echo '- Все -'
echo ${VarSomething:0} # все не пустые символы
echo ${ArrayVar[@]:0} # все не пустые элементы
echo ${@:0} # все не пустые параметры;
# параметр [0] игнорируется
echo
echo '- Все после -'
echo ${VarSomething:1} # все не пустые символы, стоящие после [0]
echo ${ArrayVar[@]:1} # все не пустые элементы, стоящие после [0]
echo ${@:2} # все не пустые параметры, стоящие после [1]
echo
echo '- Диапазон символов -'
echo ${VarSomething:4:3} # ral
# Три символа, следующие
# за символом [3]
echo '- Разреженный массив -'
echo ${ArrayVar[@]:1:2} # four - Единственный непустой элемент.
# Чтобы убедиться в том, что Bash в данной ситуации рассматривает только
#+ непустые элементы
# printf %q "${ArrayVar[@]:0:3}" # Попробуйте раскомментарить эту строку
# Версии Bash 2.04, 2.05a и 2.05b,
#+ работают с разреженными массивами не так как ожидается.
#
# Chet Ramey обещал исправить это в последующих версиях Bash.
echo '- Неразреженный массив -'
echo ${@:2:2} # За параметром [1] следуют еще два параметра
# Простые примеры со строками и массивами строк:
stringZ=abcABC123ABCabc
arrayZ=( abcabc ABCABC 123123 ABCABC abcabc )
sparseZ=( [1]='abcabc' [3]='ABCABC' [4]='' [5]='123123' )
echo
echo ' - - Простая строка - -'$stringZ'- - '
echo ' - - Простой массив - -'${arrayZ[@]}'- - '
echo ' - - Разреженный массив - -'${sparseZ[@]}'- - '
echo ' - [0]==нет элемента, [2]==нет элемента, [4]==пустой элемент - '
echo ' - [1]=abcabc [3]=ABCABC [5]=123123 - '
echo ' - количество инициализированных элементов: '${#sparseZ[@]}
echo
echo '- - Префиксы - -'
echo '- - Шаблон должен совпадать с первым символом строки. - -'
echo '- - Шаблон может быть строкой или результатом работы функции. - -'
echo
# Функция, результатом работы которой является обычная строка
_abc() {
echo -n 'abc'
}
echo '- Кратчайший префикс -'
echo ${stringZ#123} # Без изменения — не префикс.
echo ${stringZ#$(_abc)} # ABC123ABCabc
echo ${arrayZ[@]#abc} # Применяется к каждому элементу массива.
# Chet Ramey обещал исправить в последующих версиях Bash.
# echo ${sparseZ[@]#abc} # В версии 2.05b — core dumps.
# -Это было бы здорово- First-Subscript-Of (Первый-Индекс-Массива)
# echo ${#sparseZ[@]#*} # line 805: ${#sparseZ[@]#*}: bad substitution.
echo
echo '- Наибольший префикс -'
echo ${stringZ##1*3} # Без изменения — не префикс.
echo ${stringZ##a*C} # abc
echo ${arrayZ[@]##a*c} # ABCABC 123123 ABCABC
# Chet Ramey обещал исправить в последующих версиях Bash.
# echo ${sparseZ[@]##a*c} # В версии 2.05b — core dumps.
echo
echo '- - Суффиксы - -'
echo '- - Шаблон должен совпадать с последним символом строки. - -'
echo '- - Шаблон может быть строкой или результатом работы функции. - -'
echo
echo '- Кратчайший суффикс -'
echo ${stringZ%1*3} # Без изменения — не суффикс.
echo ${stringZ%$(_abc)} # abcABC123ABC
echo ${arrayZ[@]%abc} # Применяется к каждому элементу массива.
# Chet Ramey обещал исправить в последующих версиях Bash.
# echo ${sparseZ[@]%abc} # В версии 2.05b — core dumps.
# -Это было бы здорово- Last-Subscript-Of (Последний-Индекс-Массива)
# echo ${#sparseZ[@]%*} # line 830: ${#sparseZ[@]%*}: bad substitution
echo
echo '- Наибольший суффикс -'
echo ${stringZ%%1*3} # Без изменения — не суффикс.
echo ${stringZ%%b*c} # a
echo ${arrayZ[@]%%b*c} # a ABCABC 123123 ABCABC a
# Chet Ramey обещал исправить в последующих версиях Bash.
# echo ${sparseZ[@]%%b*c} # В версии 2.05b — core dumps.
echo
echo '- - Замена подстроки - -'
echo '- - Подстрока может находиться в любом месте в строке. - -'
echo '- - Первый описатель задает шаблон поиска - -'
echo '- - Шаблон может быть строкой или результатом работы функции. - -'
echo '- - Второй описатель может быть строкой или результатом работы функции. - -'
echo '- - Второй описатель может быть опущен. В результате получится:'
echo ' Заменить-Ничем (Удалить) - -'
echo
# Функция, результатом работы которой является обычная строка
_123() {
echo -n '123'
}
echo '- Замена первого вхождения -'
echo ${stringZ/$(_123)/999} # Подстрока 123 заменена на 999).
echo ${stringZ/ABC/xyz} # xyzABC123ABCabc
echo ${arrayZ[@]/ABC/xyz} # Применяется ко всем элементам массива.
echo ${sparseZ[@]/ABC/xyz} # Работает так как и ожидается.
echo
echo '- Удаление первого вхождения -'
echo ${stringZ/$(_123)/}
echo ${stringZ/ABC/}
echo ${arrayZ[@]/ABC/}
echo ${sparseZ[@]/ABC/}
# Замещающий элемент необязательно должен быть строкой,
#+ допускается употреблять результат функции.
# Это применимо ко всем формам замены.
echo
echo '- Замена первого вхождения результатом работы функции -'
echo ${stringZ/$(_123)/$(_simple)} # Работает так как и ожидается.
echo ${arrayZ[@]/ca/$(_simple)} # Применяется ко всем элементам массива.
echo ${sparseZ[@]/ca/$(_simple)} # Работает так как и ожидается.
echo
echo '- Замена всех вхождений -'
echo ${stringZ//[b2]/X} # все символы b и 2 заменяются символом X
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
echo ${arrayZ[@]//abc/xyz} # Применяется ко всем элементам массива.
echo ${sparseZ[@]//abc/xyz} # Работает так как и ожидается.
echo
echo '- Удаление всех вхождений -'
echo ${stringZ//[b2]/}
echo ${stringZ//abc/}
echo ${arrayZ[@]//abc/}
echo ${sparseZ[@]//abc/}
echo
echo '- - Замена префикса - -'
echo '- - Шаблон должен совпадать с первым символом строки. - -'
echo
echo '- - Замена префикса - -'
echo ${stringZ/#[b2]/X} # Без изменения — не префикс.
echo ${stringZ/#$(_abc)/XYZ} # XYZABC123ABCabc
echo ${arrayZ[@]/#abc/XYZ} # Применяется ко всем элементам массива.
echo ${sparseZ[@]/#abc/XYZ} # Работает так как и ожидается.
echo
echo '- Удаление префикса -'
echo ${stringZ/#[b2]/}
echo ${stringZ/#$(_abc)/}
echo ${arrayZ[@]/#abc/}
echo ${sparseZ[@]/#abc/}
echo
echo '- - Замена суффикса - -'
echo '- - Шаблон должен совпадать с последним символом строки. - -'
echo
echo '- - Замена суффикса - -'
echo ${stringZ/%[b2]/X} # Без изменения — не суффикс.
echo ${stringZ/%$(_abc)/XYZ} # abcABC123ABCXYZ
echo ${arrayZ[@]/%abc/XYZ} # Применяется ко всем элементам массива.
echo ${sparseZ[@]/%abc/XYZ} # Работает так как и ожидается.
echo
echo '- Удаление суффикса -'
echo ${stringZ/%[b2]/}
echo ${stringZ/%$(_abc)/}
echo ${arrayZ[@]/%abc/}
echo ${sparseZ[@]/%abc/}
echo
echo '- - Специальный случай — пустой шаблон поиска - -'
echo
echo '- Префикс -'
# пустой шаблон означает простую вставку в начало строки
echo ${stringZ/#/NEW} # NEWabcABC123ABCabc
echo ${arrayZ[@]/#/NEW} # Применяется ко всем элементам массива.
echo ${sparseZ[@]/#/NEW} # И к неинициализированным элементам тоже
echo
echo '- Суффикс -'
# пустой шаблон означает простое добавление в конец строки
echo ${stringZ/%/NEW} # abcABC123ABCabcNEW
echo ${arrayZ[@]/%/NEW} # Применяется ко всем элементам массива.
echo ${sparseZ[@]/%/NEW} # И к неинициализированным элементам тоже
echo
echo '- - Специальный случай оператора For-Each - -'
echo '- - - - This is a nice-to-have dream - - - -'
echo
_GenFunc() {
echo -n ${0} # Только как иллюстрация.
# Фактически здесь может стоять любое другое выражение.
}
# Все вхождения, совпадающие с шаблоном "*"
# В настоящее время, шаблон //*/ не совпадает с пустыми
#+ и неинициализированными элементами.
# В то время как шаблоны /#/ и /%/ совпадают с пустыми и не совпадают
#+ с неинициализированными элементами.
echo ${sparseZ[@]//*/$(_GenFunc)}
exit 0
Последние комментарии