Перечисление переменных оболочки с фиксированным префиксом

Я посмотрел это и не могу найти ответ, заранее прошу прощения, если его уже спрашивали

Я использую оболочку во FreeBSD ( /bin/sh ) и хочу получить дамп для вывода всех переменных оболочки ( не окружения), начиная с _myvar_ . Самый близкий, который я могу получить, set | grep '^_myvar_' set | grep '^_myvar_' но он set | grep '^_myvar_' только первую строку многострочных переменных (некоторые будут многострочными, и они мне понадобятся полностью), и это может быть подвержено ошибкам в случаях патологических краев, таких как строка, содержащая ” myvar “, которая встречается со строкой разбить как раз перед этой частью.

если бы я мог перечислить только имена переменных (не значения), то я мог бы фильтровать в do...read...while и получать значения по одному только для переменных с совпадающими именами, но я не могу найти способ сделать это. Я также не могу отфильтровать полный вывод, потому что не существует детерминированного способа определить, содержит ли выходная строка продолжение или новую переменную, у которого нет проблем с краями в случае строк, содержащих _myvar_ , = или newline (\n) символы или, возможно, завершающие пробелы. Я не хочу изменять среду, потому что код включен в другой код, и среда должна быть стабильной для него.

Для выходных данных / списка не является проблемой включение любых соответствующих переменных среды, если это помогает (если таковые существуют – крайне маловероятно, что они будут)

Есть ли способ сделать это?

Поскольку встроенный set FreeBSD sh выводит в формате, который подходит для повторного ввода в оболочку, вы можете сделать:

 out() case $1 in (_myvar_*) printf '%s\n' "${1%%=*}"; esac eval "$(set | sed 's/^/out /')" 

То есть префикс каждой строки выходных данных set с "out " , который оценивается как код оболочки (где out – функция, которая печатает подстроку своего первого аргумента вплоть до первого = ).

sed также вставляет "out " в содержимое многострочной переменной, но это все равно будет включено в аргумент, который наша функция out получает и после first = , поэтому в той части, которую мы не отображаем.

Например, на выходе set например:

 TERM=xterm USER=stephane _myvar_foo='line1 line2 line3' 

Мы будем оценивать:

 out TERM=xterm out USER=stephane out _myvar_foo='line1 out line2 out line3' 

Но это все еще хорошо, так как out вызывается только 3 раза для этих 3 переменных.

Чтобы напечатать имя и значение переменной:

 out() case $1 in (_myvar_*) eval 'printf "name: \"%s\" value: \"%s\"\n" "${1%%=*}" "${'"${1%%=*}"'}"' esac eval "$(set | sed 's/^/out /')" 

Обратите внимание, что он выводит только переменные , а не другие типы параметров, такие как $- , позиционные параметры …

Этот подход работает только для реализаций sh где set выводит только скалярные переменные (не будет работать для массивов, ассоциативных массивов или составных переменных, где out var=(x) становится синтаксической ошибкой). Те оболочки, которые имеют другие типы переменных, также часто имеют лучшие функции самоанализа.

В zsh :

 typeset -pm '_myvar_*' 

или только для имен

 echo $parameters[(I)_myvar_*] 

В bash :

 v=("${!_myvar_@}"); ((${#v[@]})) && typeset -p -- "${v[@]}" echo "${!_myvar_@}" 

Я закончил со следующим упрощением решения @ StéphaneChazelas, потому что мне не нужно больше. Разместите его ниже, если это кому-нибудь поможет. Но Стефан нашел ответ, это всего лишь модифицированная версия, не более того.

 #!/bin/sh get_vars() { if printf '%s' "$1" | grep -qE '^_myvar_'; then printf '%s\n' "$1" | sed 's/^get_vars //' fi } eval "$( set | sed 's/^/get_vars /' )" 

Вызов eval get_vars VARNAME=VALUE каждой строки, но из-за способа, которым set выводит свои значения, он фактически создает единственную команду get_vars VARNAME=VALUE для каждой переменной. Оценка этого выполняет команды. Затем каждый раз, когда он get_vars , get_vars проверяет, соответствует ли переменная, захваченная в текущей строке, необходимому регулярному выражению, и, если это так, удаляет префикс "get_vars " из любой второй и последующих строк и отображает результат.