Как перечислить переменные, объявленные в скрипте в Bash? - PullRequest
81 голосов
/ 20 августа 2009

В моем скрипте в bash много переменных, и мне нужно что-то сделать, чтобы сохранить их в файл. У меня вопрос, как составить список всех переменных, объявленных в моем скрипте, и получить список следующим образом:

VARIABLE1=abc
VARIABLE2=def
VARIABLE3=ghi

Ответы [ 11 ]

134 голосов
/ 20 августа 2009

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

(или, по крайней мере, что-то основанное на этом :-))

33 голосов
/ 02 мая 2013
compgen -v

В нем перечислены все переменные, включая локальные. Я узнал это из Получил список переменных, чье имя соответствует определенному шаблону , и использовал его в моем скрипте .

9 голосов
/ 09 марта 2012
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
4 голосов
/ 15 августа 2017

Основываясь на некоторых из приведенных выше ответов, это сработало для меня:

before=$(set -o posix; set | sort);

исходный файл :

comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq) 
3 голосов
/ 20 августа 2009

Если вы можете выполнить постобработку (как уже упоминалось), вы можете просто сделать вызов set в начале и конце вашего скрипта (каждый в другой файл) и выполнить 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
1 голос
/ 03 января 2018

Вот что-то похожее на ответ @GinkgoFr, но без проблем, выявленных @Tino или @DejayClayton, и является более надежным, чем умный set -o posix бит @ DouglasLeeder:

+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }

Разница в том, что это решение ОСТАНАВЛИВАЕТСЯ после первого не переменного отчета, например, первая функция, о которой сообщает set

Кстати: проблема "Тино" решена. Даже если POSIX выключен, а о функциях сообщается set, * * * * * часть решения позволяет только через переменные отчеты (например, 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% уверенность в том, что <code>set всегда преобразует переводы строки в значение в \n, что зависит от этого решения чтобы избежать проблемы "DejayClayton". Возможно, это современное поведение? Или вариант во время компиляции? Или параметр set -o или shopt? Если вы знаете о таких вариациях, пожалуйста, добавьте комментарий ...

0 голосов
/ 08 марта 2019

Команда printenv:

printenv печатает все environment variables вместе с их значениями.

Удачи ...

0 голосов
/ 10 мая 2017

Я, вероятно, украл ответ в то время как назад ... во всяком случае, немного отличается от функа:

    ##
    # 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"
    } 
0 голосов
/ 03 марта 2017

Попробуйте: set | egrep "^\w+=" (с или без | less трубопровода)

Первое предложенное решение, ( set -o posix ; set ) | less, работает, но имеет недостаток: оно передает контрольные коды на терминал, поэтому они не отображаются должным образом. Так, например, если есть переменная (вероятно) IFS=$' \t\n', мы можем увидеть:

IFS='
'

... вместо этого.

Мое egrep решение отображает это (и, возможно, другие подобные) правильно.

0 голосов
/ 16 декабря 2016

С точки зрения безопасности, либо @ akostadinov's answer , либо @ JuvenXu's 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, чтобы определить, является ли сценарий интерактивным или нет (не берите в голову, что это лучший способ достичь этой цели; это всего лишь пример.)

Однако вывод set является неструктурированным, что означает, что любая переменная, содержащая символ новой строки, может полностью загрязнить результаты.

Это, конечно, потенциальная угроза безопасности. Вместо этого используйте поддержку Bash для косвенного расширения имени переменной или compgen -v.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...