В моем скрипте на bash много переменных, и мне нужно что-то сделать, чтобы сохранить их в файл. Мой вопрос в том, как перечислить все переменные, объявленные в моем скрипте, и получить такой список:
VARIABLE1=abc
VARIABLE2=def
VARIABLE3=ghi
Ответы:
set
выводит переменные, но, к сожалению, также выводит определения функций.
К счастью, режим POSIX выводит только переменные:
( set -o posix ; set ) | less
Подключение по конвейеру less
или перенаправление туда, где вам нужны параметры.
Итак, чтобы получить переменные, объявленные только в скрипте:
( 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
(Или хотя бы что-то на этом основании :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;
. Это также выведет вары в формате, готовом к сохранению. В список будут включены переменные, которые скрипт изменил (
source
, вы должны иметь возможность сделать это с помощью вывода declare -p
.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
В нем перечислены все переменные, включая локальные. Я узнал его из списка переменных, имя которых соответствует определенному шаблону , и использовал его в своем скрипте .
compgen -v
перечислены также глобальные переменные, которые не были установлены локально. Не уверен, что это давняя ошибка или желаемое поведение.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Это должно напечатать все имена переменных оболочки. Вы можете получить список до и после получения вашего файла, как и с помощью «set», чтобы определить, какие переменные являются новыми (как описано в других ответах). Но имейте в виду, что такая фильтрация с помощью diff может отфильтровать некоторые переменные, которые вам нужны, но присутствовали до источника вашего файла.
В вашем случае, если вы знаете, что имена ваших переменных начинаются с «VARIABLE», вы можете создать свой скрипт и сделать:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
ОБНОВЛЕНИЕ: для чистого решения BASH (внешние команды не используются):
for i in _ {a..z} {A..Z}; do
for var in `eval echo "\\${!$i@}"`; do
echo $var
# you can test if $var matches some criteria and put it in the file or ignore
done
done
eval "printf '%q\n' $(printf ' "${!%s@}"' _ {a..z} {A..Z})"
Основываясь на некоторых из приведенных выше ответов, это сработало для меня:
before=$(set -o posix; set | sort);
исходный файл :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Если вы можете set
выполнить пост-обработку (как уже упоминалось), вы можете просто разместить вызов в начале и в конце вашего скрипта (каждый для другого файла) и провести различие между двумя файлами. Поймите, что это все еще будет содержать некоторый шум.
Вы также можете сделать это программно. Чтобы ограничить вывод только вашей текущей областью, вам нужно будет реализовать оболочку для создания переменной. Например
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
Вот что-то похожее на ответ @GinkgoFr, но без проблем, выявленных @Tino или @DejayClayton, и более надежное, чем умный set -o posix
бит @DouglasLeeder :
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
Разница в том, что это решение ОСТАНАВЛИВАЕТСЯ после первого неизменяемого отчета, например, первой функции, о которой сообщает set
Кстати: проблема "Тино" решена. Несмотря на то, что POSIX отключен, а функции передаются через set
, sed ...
часть решения разрешает только отчеты с переменными (например, VAR=VALUE
строки). В частности, A2
он не попадает в выходные данные ложным образом.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
И: Проблема "DejayClayton" решена (встроенные символы новой строки в значениях переменных не нарушают вывод - каждый VAR=VALUE
выводит одну строку):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
ПРИМЕЧАНИЕ. Решение, предоставленное @DouglasLeeder, страдает от проблемы «DejayClayton» (значения со встроенными символами новой строки). Ниже показано A1
неправильное изображение, которое A2
вообще не должно отображаться.
$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999
НАКОНЕЦ: Я не думаю, что версия имеет bash
значение, но может. Я провел тестирование / разработку на этом:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: Учитывая некоторые другие ответы на OP, я на <100% уверен, что set
всегда преобразует символы новой строки в пределах значения \n
, на которое полагается это решение, чтобы избежать проблемы "DejayClayton". Может, это современное поведение? Или вариация времени компиляции? Или параметр set -o
или shopt
параметр? Если вам известны такие варианты, оставьте комментарий ...
С точки зрения безопасности, либо @ akostadinov - х ответ или @ JuvenXu - х ответ предпочтительнее полагаться на неструктурированной выходе 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
чтобы определить, является ли сценарий интерактивным или нет (неважно, если это лучший способ достичь этой цели; это всего лишь пример).
Однако вывод set
неструктурирован, а это означает, что любая переменная, содержащая новую строку, может полностью испортить результаты.
Это, конечно, потенциальная угроза безопасности. Вместо этого используйте либо поддержку Bash для косвенного раскрытия имени переменной, либо compgen -v
.
Попробуйте это: set | egrep "^\w+="
(с | less
трубопроводом или без него )
Первое предложенное решение ( set -o posix ; set ) | less
работает, но имеет недостаток: оно передает управляющие коды на терминал, поэтому они не отображаются должным образом. Так, например, если есть (вероятно)IFS=$' \t\n'
переменное, мы можем видеть:
IFS='
'
…вместо.
Мое egrep
решение отображает это (и, в конечном итоге, другие похожие) правильно.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A
отображение A=B"
-> Ошибка!
Я, наверное, украл ответ какое-то время назад ... во всяком случае, немного отличается от функции:
##
# 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"
}
Простой способ сделать это - использовать строгий режим bash , установив системные переменные среды перед запуском вашего скрипта, и использовать diff для сортировки только тех из вашего скрипта:
# Add this line at the top of your script :
set > /tmp/old_vars.log
# Add this line at the end of your script :
set > /tmp/new_vars.log
# Alternatively you can remove unwanted variables with grep (e.g., passwords) :
set | grep -v "PASSWORD1=\|PASSWORD2=\|PASSWORD3=" > /tmp/new_vars.log
# Now you can compare to sort variables of your script :
diff /tmp/old_vars.log /tmp/new_vars.log | grep "^>" > /tmp/script_vars.log
Теперь вы можете получить переменные вашего скрипта в /tmp/script_vars.log. Или хотя бы что-то на этом основании!
Немного поздно на вечеринку, но вот еще одно предложение:
#!/bin/bash
set_before=$( set -o posix; set | sed -e '/^_=*/d' )
# create/set some variables
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
set_after=$( set -o posix; unset set_before; set | sed -e '/^_=/d' )
diff <(echo "$set_before") <(echo "$set_after") | sed -e 's/^> //' -e '/^[[:digit:]].*/d'
Diff + СЭД командной строка трубопроводов выводит весь сценарий определенных переменные в нужном формате (как указано в посте ОП в):
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
-o posix
now a diff будет содержать только переменные.