#! /bin/bash
# protect_literal.sh
# set -vx
:<<-'_Protect_Literal_String_Doc'
Copyright (c) Michael S. Zick, 2003; All Rights Reserved
Ограничения: Допускается использовать без каких либо ограничений в любой форме.
Гарантии: Никаких
Издание: $ID$
Этот встроенный документ Bash отправит на устройство '/dev/null'.
(Раскомментарьте команду set, стоящую выше, чтобы убедиться в этом.)
Удалите первую строку (Sha-Bang), если вы собираетесь использовать этот сценарий
в качестве библиотеки. Не забудьте при этом закомментарить примеры
использования процедур (там где это указано).
Порядок использования:
_protect_literal_str 'Whatever string meets your ${fancy}'
Какая бы строка ни была передана функции,
она просто будет выведена на stdout,
включая "строгие" кавычки.
$(_protect_literal_str 'Whatever string meets your ${fancy}')
как правосторонняя часть операции присваивания.
Назначение:
В операциях присваивания, предотвращают дополнительную
интерпретацию содержимого строки, путем добавления "строгих"
кавычек.
Примечание:
Имена функций (_*) выбраны таким образом, чтобы избежать
конфликтов имен, при подключении данного сценария
к пользовательским сценариям, в качестве библиотеки.
_Protect_Literal_String_Doc
_protect_literal_str() {
# Выберем неиспользуемый, непечатный символ в качестве разделителя полей для IFS.
# В этом нет необходимости, но делается это для демогстрации
# того, что разделитель полей игнорируется.
local IFS=$'\x1B' # Символ \ESC
# Заключим Все-Элементы в "строгие" кавычки.
local tmp=$'\x27'$@$'\x27'
local len=${#tmp} # Исключительно для демонстрации.
echo $tmp, длина:$len. # Вывод строки и дополнительной информации.
}
# Версия с более коротким именем.
_pls() {
local IFS=$'x1B' # Символ \ESC (не обязательно)
echo $'\x27'$@$'\x27' # Заключить в "строгие" кавычки
}
# :<<-'_Protect_Literal_String_Test'
# # # Раскомментарьте вышестоящую строку, чтобы запретить исполнение нижеследующего кода. # # #
# Посмотрим как выглядит простой вывод.
echo
echo "- - Тест #1 - -"
_protect_literal_str 'Hello $user'
_protect_literal_str 'Hello "${username}"'
echo
# В результате должно получиться:
# - - Тест #1 - -
# 'Hello $user', длина: 13.
# 'Hello "${username}"', длина: 21.
# Собственно получили то, что и ожидали, тогда в чем проблема?
# Проблема скрыта внутри Bash, в порядке выполнения операций.
# Она проявляется, когда функции учавствуют в операциях присваивания.
# Объявим массив тестовых значений.
declare -a arrayZ
# Запишем в массив элементы с разного рода кавычками и экранирующими символами.
arrayZ=( zero "$(_pls 'Hello ${Me}')" 'Hello ${You}' "\'Pass: ${pw}\'" )
# Теперь выведем массив на экран и посмотрим, что там лежит.
echo "- - Тест #2 - -"
for (( i=0 ; i<${#arrayZ[*]} ; i++ ))
do
echo Элемент $i: ${arrayZ[$i]}, длина: ${#arrayZ[$i]}.
done
echo
# В результате должно получиться:
# - - Тест #2 - -
# Элемент 0: zero, длина: 4. # Маркировочный (ничем не примечательный) элемент
# Элемент 1: 'Hello ${Me}', длина: 13. # Результат "$(_pls '...' )"
# Элемент 2: Hello ${You}, длина: 12. # Кавычки исчезли
# Элемент 3: \'Pass: \', длина: 10. # ${pw} — была интерпретирована,
# # а на ее место подставлена пустая строка
# Выполним присвоение одного массива другому.
declare -a array2=( ${arrayZ[@]} )
# И выведем его содержимое.
echo "- - Тест #3 - -"
for (( i=0 ; i<${#array2[*]} ; i++ ))
do
echo Элемент $i: ${array2[$i]}, длина: ${#array2[$i]}.
done
echo
# В результате должно получиться:
# - - Тест #3 - -
# Элемент 0: zero, длина: 4. # Наш маркер.
# Элемент 1: Hello ${Me}, длина: 11. # Вполне предсказуемый результат.
# Элемент 2: Hello, длина: 5. # ${You} — была интерпретирована.
# # а на ее место подставлена пустая строка
# Элемент 3: 'Pass:, длина: 6. # Элемент был "разбит" на два по пробелу.
# Элемент 4: ', длина: 1. # Завершающая кавычка попала в отдельный элемент.
# В Элементе 1 были удалены начальная и завершающая "строгие" кавычки.
# Хотя здесь и не показано, но начальные и звершающие пробелы также удаляются.
# Теперь, когда содержимое строки установлено, Bash всегда, внутри, будет
# "строго" окавычивать содержимое строки, на протяжении всей операции
# Зачем это нужно?
# В нашем случае, в конструкции "$(_pls 'Hello ${Me}')":
# " ... " -> Требуется интерпретация (экспансия), кавычки удаляются.
# $( ... ) -> Замещается результатом выполнения ..., пустая строка.
# _pls ' ... ' -> вызов функции со строковым аргументом, кавычки удаляются.
# Возвращаемый результат включает в себя "строгие" кавычки; НО обработка команды
#+ уже была завершена выше, так что теперь они становятся частью присваиваемого
#+ значения.
#
# Таким образом, ${Me} оказывается частью результата
#+ и сохраняется в первоначальном виде
# (До тех пор, пока явно не будет указано на необходимость ее интерпретации).
# Дополнительно: Взгляните, что произойдет, если в этих функциях
#+ "строгие" кавычки ($'\x27') заменить на "мягкие" ($'\x22').
# Интересный результат получится если вообще убрать кавычки.
# _Protect_Literal_String_Test
# # # Раскомментарьте вышестоящую строку, чтобы запретить исполнение вышестоящего кода. # # #
exit 0
Последние комментарии