#bash #eval #code-injection #curly-braces #variable-expansion
#bash #eval #внедрение кода #фигурные скобки #переменная-расширение
Вопрос:
Учитывая строковую переменную (не строку) в bash, как можно развернуть ее фигурные скобки (и добавить любые подстановочные знаки файла, такие как звездочки), а затем сохранить результирующее расширение в массиве?
Я знаю, что это возможно с eval
:
#!/usr/bin/env bash
string="{a,b}{1,2}"
array=( $( eval echo $string ) )
echo "${array[@]}"
#a1 a2 b1 b2
Но eval
это может быть опасно, если мы не доверяем содержимому string
(скажем, если это аргумент скрипта). A string
со встроенными точками с запятой, кавычками, пробелами, произвольными командами и т. Д. Может Открыть скрипт для атаки.
Есть ли более безопасный способ сделать это расширение в bash? Я подозреваю, что все следующие одинаково небезопасные способы расширения строки:
#!/usr/bin/env bash
eval echo $string
bash <<< "echo $string"
echo echo $string | bash
bash <(echo echo $string)
Возможно, есть команда, отличная от bash, к которой мы можем передать строку, которая выполнит расширение?
В стороне: обратите внимание, что в csh / tcsh это легко, поскольку расширение фигурных скобок происходит после замены переменной (в отличие от bash):
#!/usr/bin/env csh
set string = "{a,b}{1,2}"
set array = ( $string )
echo "$array"
#a1 a2 b1 b2
Комментарии:
1. Назначения массива расширяют расширения фигурных скобок, не
eval
требуется! Попробуйтеarr=({1,2}); declare -p arr
2. О, подождите, вы начинаете со строковой переменной. Это не сработает, потому что расширение фигурных скобок происходит до расширения параметра.
3. Откуда вы
string
беретесь? Возможно, есть способ выполнить расширение фигурных скобок на отдельном шаге.4. Действительно, я начинаю со строковой переменной, а не строки, и хочу развернуть ее в массив. В моем приложении строковая переменная обычно длинная и сложная с фигурными скобками, подстановочными знаками и т. Д. И расширяется в очень длинный массив файлов. Строка также используется в ее нерасширенной форме в другом месте скрипта, например, передается другим командам оболочки, Которые позже будут выполнять расширение после добавления путей и т. Д., Поэтому рефакторинг моего кода, чтобы избежать этого, будет сложным.
5. Звучит так, как будто передача уже расширенного списка вместо чего-то подобного
'a{b,c}*'
была бы предпочтительнее. Конечно, это усложняет другие задачи, но это не хакерский подход. Кроме этого, мне бы очень хотелось увидеть ответ на вопрос вместо комментариев, подобных моим (пытаясь убедить вас не делать то, что вы хотели 🙂
Ответ №1:
braceexpand
Модуль Python в сочетании с модулем стандартной библиотеки glob
можно использовать для достижения того, что вы ищете. Завернутый в оболочку для использования из bash, это может выглядеть так:
#!/usr/bin/env bash
case $BASH_VERSION in
''|[123].*|4.[012].*) echo "ERROR: bash 4.3 required" >amp;2; exit 1;;
esac
# store Python code in a string
expand_py=$(cat <<'EOF'
try:
import sys, glob, braceexpand
except ImportError as e:
sys.stderr.write("Did you remember to install the braceexpand Python module?n")
raise e
for arg in sys.argv[1:]:
for globexp in braceexpand.braceexpand(arg):
glob_results = glob.glob(globexp)
if len(glob_results) == 0:
sys.stdout.write(globexp)
sys.stdout.write('')
continue
else:
sys.stdout.write(''.join(['%s' % result for result in glob_results]))
EOF
)
# shell wrapper for the above Python program
expand() {
local item
local -n dest_array=$1; shift
dest_array=( )
while IFS= read -r -d '' item; do
dest_array =( "$item" )
done < <(python3 -c "$expand_py" "$@")
unset -n dest_array
}
# actually demonstrate usage
expand yourArray '{a,b}{1,2}'
declare -p yourArray
…выводит при запуске заданное значение массива:
declare -a yourArray=([0]="a1" [1]="a2" [2]="b1" [3]="b2")