Как перечислить переменные, объявленные в script в bash?
В моем script в bash есть много переменных, и я должен что-то сделать, чтобы сохранить их в файл.
Мой вопрос заключается в том, как перечислить все переменные, объявленные в моем script, и получить список следующим образом:
VARIABLE1=abc
VARIABLE2=def
VARIABLE3=ghi
Ответы
Ответ 1
set
выдаст переменные, к сожалению, он также выведет также функции.
К счастью, режим POSIX выводит только переменные:
( set -o posix ; set ) | less
Трубопровод до less
или перенаправление туда, где вы хотите.
Итак, чтобы получить переменные, объявленные только в script:
( set -o posix ; set ) >/tmp/variables.before
source script
( set -o posix ; set ) >/tmp/variables.after
diff /tmp/variables.before /tmp/variables.after
rm /tmp/variables.before /tmp/variables.after
(Или, по крайней мере, что-то, основанное на этом:-))
Ответ 2
compgen -v
В нем перечислены все переменные, включая локальные.
Я узнал его из bash: получить список переменных, имя которых соответствует определенному шаблону, и использовать его в my script.
Ответ 3
for i in _ {a..z} {A..Z}; do eval "echo \${[email protected]}" ; done | xargs printf "%s\n"
Это должно печатать все имена переменных оболочки. Вы можете получить список до и после поиска вашего файла, как с помощью "set", чтобы определить, какие переменные являются новыми (как объясняется в других ответах). Но имейте в виду, что такая фильтрация с diff может отфильтровывать некоторые переменные, которые вам нужны, но присутствовали до поиска вашего файла.
В вашем случае, если вы знаете, что имена ваших переменных начинаются с "VARIABLE", вы можете указать свой script и сделать:
for var in ${[email protected]}; do
printf "%s%q\n" "$var=" "${!var}"
done
UPDATE: Для чистого решения BASH (без внешних команд):
for i in _ {a..z} {A..Z}; do
for var in `eval echo "\\${[email protected]}"`; do
echo $var
# you can test if $var matches some criteria and put it in the file or ignore
done
done
Ответ 4
Если вы можете выполнять пост-обработку (как уже упоминалось), вы можете просто поместить вызов set
в начале и конце вашего script (каждый в другой файл) и выполнить diff для двух файлов. Поймите, что это все равно будет содержать некоторый шум.
Вы также можете сделать это программно. Чтобы ограничить вывод только вашей текущей областью, вам придется реализовать оболочку для создания переменной. Например
store() {
export ${1}="${*:2}"
[[ ${STORED} =~ "(^| )${1}($| )" ]] || STORED="${STORED} ${1}"
}
store VAR1 abc
store VAR2 bcd
store VAR3 cde
for i in ${STORED}; do
echo "${i}=${!i}"
done
Что дает
VAR1=abc
VAR2=bcd
VAR3=cde
Ответ 5
Основываясь на некоторых из приведенных выше ответов, это сработало для меня:
before=$(set -o posix; set | sort);
исходный файл:
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Ответ 6
Попробуйте использовать script (давайте назовем его "ls_vars" ):
#!/bin/bash
set -a
env > /tmp/a
source $1
env > /tmp/b
diff /tmp/{a,b} | sed -ne 's/^> //p'
chmod + x it и:
ls_vars your-script.sh > vars.files.save
Ответ 7
С точки зрения безопасности, либо @akostadinov answer, либо @JuvenXu answer предпочтительнее полагаться на неструктурированный вывод команды set
из-за следующего потенциального недостатка безопасности:
#!/bin/bash
function doLogic()
{
local COMMAND="${1}"
if ( set -o posix; set | grep -q '^PS1=' )
then
echo 'Script is interactive'
else
echo 'Script is NOT interactive'
fi
}
doLogic 'hello' # Script is NOT interactive
doLogic $'\nPS1=' # Script is interactive
В приведенной выше функции doLogic
используется set
для проверки наличия переменной PS1
, чтобы определить, является ли script интерактивным или нет (неважно, является ли это наилучшим способом достижения этой цели; просто пример.)
Однако вывод set
неструктурирован, что означает, что любая переменная, содержащая новую строку, может полностью загрязнить результаты.
Это, конечно, потенциальный риск для безопасности. Вместо этого используйте поддержку Bash для расширения имени косвенной переменной или compgen -v
.
Ответ 8
Попробуйте следующее: set | egrep "^\w+="
(с трубопроводом | less
или без него)
Первое предлагаемое решение ( set -o posix ; set ) | less
работает, но имеет недостаток: он передает управляющие коды терминалу, поэтому они отображаются неправильно. Например, если есть (вероятно) переменная IFS=$' \t\n'
, мы можем видеть:
IFS='
'
... вместо этого.
My egrep
решение отображает это (и в конечном итоге другие аналогичные) правильно.
Ответ 9
Я, вероятно, недавно украл ответ... в любом случае немного отличается как func:
##
# usage source bin/nps-bash-util-funcs
# doEchoVars
doEchoVars(){
# if the tmp dir does not exist
test -z ${tmp_dir} && \
export tmp_dir="$(cd "$(dirname $0)/../../.."; pwd)""/dat/log/.tmp.$$" && \
mkdir -p "$tmp_dir" && \
( set -o posix ; set )| sort >"$tmp_dir/.vars.before"
( set -o posix ; set ) | sort >"$tmp_dir/.vars.after"
cmd="$(comm -3 $tmp_dir/.vars.before $tmp_dir/.vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
echo -e "$cmd"
}