Odpowiedzi:
set
wypisze zmienne, niestety wypisze również definicje funkcji.
Na szczęście tryb POSIX wyświetla tylko zmienne:
( set -o posix ; set ) | less
Piping do less
lub przekierowanie do miejsca, w którym chcesz mieć opcje.
Aby uzyskać zmienne zadeklarowane tylko w skrypcie:
( 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
(A przynajmniej coś na tej podstawie :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;
. Spowoduje to również wyświetlenie zmiennych w formacie gotowym do zapisania. Lista będzie zawierała zmienne, które zmienił skrypt (zależy od tego, czy jest to pożądane)
source
, powinieneś móc to zrobić z wyjściem declare -p
.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
Zawiera listę wszystkich zmiennych, w tym lokalnych. Nauczyłem się tego z listy zmiennych Get, których nazwa pasuje do określonego wzorca , i użyłem go w moim skrypcie .
compgen -v
wymienia również zmienne globalne, które nie były ustawione lokalnie. Nie jestem pewien, czy to długotrwały błąd, czy pożądane zachowanie.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
To musi wypisać wszystkie nazwy zmiennych powłoki. Możesz otrzymać listę przed i po pobraniu pliku, tak jak przy „ustawieniu”, aby porównać, które zmienne są nowe (jak wyjaśniono w innych odpowiedziach). Pamiętaj jednak, że takie filtrowanie za pomocą diff może odfiltrować niektóre zmienne, których potrzebujesz, ale były obecne przed pozyskaniem pliku.
W Twoim przypadku, jeśli wiesz, że nazwy Twoich zmiennych zaczynają się od „VARIABLE”, możesz pobrać skrypt i wykonać:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
UPDATE: Dla czystego rozwiązania BASH (bez zewnętrznych poleceń):
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})"
Na podstawie niektórych z powyższych odpowiedzi, to zadziałało dla mnie:
before=$(set -o posix; set | sort);
plik źródłowy :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Jeśli możesz postprocesować (jak już wspomniano), możesz po prostu set
wywołać na początku i na końcu swojego skryptu (każdy do innego pliku) i zrobić różnicę na dwóch plikach. Zrozum, że nadal będzie zawierał trochę hałasu.
Możesz to również zrobić programowo. Aby ograniczyć dane wyjściowe tylko do bieżącego zakresu, należałoby zaimplementować opakowanie do tworzenia zmiennych. Na przykład
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
Co daje
VAR1=abc
VAR2=bcd
VAR3=cde
Oto coś podobnego do odpowiedzi @GinkgoFr, ale bez problemów zidentyfikowanych przez @Tino lub @DejayClayton i jest bardziej wytrzymałe niż sprytny set -o posix
kawałek @ DouglasLeeder :
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
Różnica polega na tym, że to rozwiązanie zatrzymuje się po pierwszym niezmiennym raporcie, np. Pierwszej funkcji zgłoszonej przez set
BTW: Problem „Tino” został rozwiązany. Mimo że POSIX jest wyłączony, a funkcje są raportowane przez set
, sed ...
część rozwiązania zezwala tylko na raportowanie zmiennych (np. VAR=VALUE
Wiersze). W szczególności, A2
czy nie fałszywie uczynić go do wyjścia.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
AND: Problem „DejayClayton” został rozwiązany (osadzone znaki nowej linii w wartościach zmiennych nie zakłócają wyjścia - każdy z nich VAR=VALUE
otrzymuje jedną linię wyjściową):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
UWAGA: Rozwiązanie dostarczone przez @DouglasLeeder cierpi na problem „DejayClayton” (wartości z osadzonymi znakami nowej linii). Poniżej A1
jest błędne i A2
nie powinno się w ogóle wyświetlać.
$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999
WRESZCIE: nie sądzę, że wersja ma bash
znaczenie, ale może. Testowałem / rozwijałem na tym:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: Biorąc pod uwagę niektóre inne odpowiedzi na OP, mam <100% pewności, że set
zawsze konwertuje znaki nowej linii w wartości \n
, na której opiera się to rozwiązanie, aby uniknąć problemu „DejayClayton”. Może to nowoczesne zachowanie? A może zmiana w czasie kompilacji? Lub ustawienie opcji set -o
lub shopt
? Jeżeli ty wiesz o takich zmian, należy dodać komentarz ...
Z punktu widzenia bezpieczeństwa, zarówno na @ akostadinov odpowiedź lub @ JuvenXu na odpowiedź korzystne jest poleganie na niestrukturalnych wyjściu set
polecenia, ze względu na następujące potencjalne luki bezpieczeństwa:
#!/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
Powyższa funkcja doLogic
służy set
do sprawdzania obecności zmiennej w PS1
celu określenia, czy skrypt jest interaktywny, czy nie (nieważne, czy jest to najlepszy sposób na osiągnięcie tego celu; to tylko przykład).
Jednak wynik set
jest nieustrukturyzowany, co oznacza, że każda zmienna zawierająca znak nowej linii może całkowicie zanieczyścić wyniki.
Jest to oczywiście potencjalne zagrożenie bezpieczeństwa. Zamiast tego użyj obsługi Bash do pośredniego rozwijania nazw zmiennych lub compgen -v
.
Spróbuj tego: set | egrep "^\w+="
(z | less
orurowaniem lub bez )
Pierwsze proponowane rozwiązanie ( set -o posix ; set ) | less
działa, ale ma wadę: przekazuje kody sterujące do terminala, więc nie są one poprawnie wyświetlane. Tak na przykład, jeśli jest (prawdopodobnie)IFS=$' \t\n'
zmienna, możemy zobaczyć:
IFS='
'
…zamiast.
Moje egrep
rozwiązanie wyświetla to (i ewentualnie inne podobne) poprawnie.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A
wyświetlacze A=B"
-> Niepowodzenie!
Prawdopodobnie ukradłem odpowiedź jakiś czas temu ... w każdym razie trochę inaczej jako 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"
}
Prostym sposobem na to jest użycie trybu ścisłego bash poprzez ustawienie zmiennych środowiskowych systemu przed uruchomieniem skryptu i użycie diff do sortowania tylko tych w skrypcie:
# 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
Możesz teraz pobrać zmienne swojego skryptu w /tmp/script_vars.log. A przynajmniej coś opartego na tym!
Trochę za późno na imprezę, ale oto kolejna sugestia:
#!/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'
Różn + sed Linia komend rurociąg wysyła wszystkie zmienne skryptów zdefiniowane w żądanym formacie (jak określono na stanowiskach w OP)
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
-o posix
różnicą now a będzie zawierało tylko zmienne.