Jawaban:
set akan menampilkan variabel, sayangnya itu juga akan menampilkan fungsi yang didefinisikan juga.
Untungnya mode POSIX hanya menampilkan variabel:
( set -o posix ; set ) | less
Mengalihkan ke less, atau mengalihkan ke tempat Anda menginginkan opsi.
Jadi untuk mendapatkan variabel yang dideklarasikan hanya dalam skrip:
( 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
(Atau setidaknya sesuatu berdasarkan itu :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;. Ini juga akan menampilkan vars dalam format yang siap disimpan. Daftar akan menyertakan variabel yang diubah skrip (tergantung apakah ini diinginkan)
source, Anda harus dapat melakukannya dengan keluaran declare -p.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
Ini mencantumkan semua variabel termasuk yang lokal. Saya mempelajarinya dari Dapatkan daftar variabel yang namanya cocok dengan pola tertentu , dan menggunakannya dalam skrip saya .
compgen -vdaftar juga variabel global yang tidak disetel secara lokal. Tidak yakin apakah itu bug lama atau perilaku yang diinginkan.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Ini harus mencetak semua nama variabel shell. Anda bisa mendapatkan daftar sebelum dan sesudah mencari file Anda seperti "set" ke diff variabel mana yang baru (seperti yang dijelaskan di jawaban lain). Namun perlu diingat bahwa pemfilteran dengan diff dapat menyaring beberapa variabel yang Anda butuhkan tetapi ada sebelum mencari file Anda.
Dalam kasus Anda, jika Anda tahu nama variabel Anda diawali dengan "VARIABEL", Anda dapat mengambil skrip Anda dan melakukan:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
UPDATE: Untuk solusi BASH murni (tidak ada perintah eksternal yang digunakan):
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})"
Berdasarkan beberapa jawaban di atas, ini berhasil untuk saya:
before=$(set -o posix; set | sort);
file sumber :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Jika Anda dapat melakukan pasca-proses, (seperti yang telah disebutkan) Anda dapat melakukan setpanggilan di awal dan akhir skrip Anda (masing-masing ke file yang berbeda) dan melakukan perbedaan pada kedua file. Sadarilah bahwa ini masih akan mengandung sedikit kebisingan.
Anda juga dapat melakukan ini secara terprogram. Untuk membatasi keluaran hanya ke lingkup Anda saat ini, Anda harus menerapkan pembungkus untuk pembuatan variabel. Sebagai contoh
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
Hasil yang mana
VAR1=abc
VAR2=bcd
VAR3=cde
Berikut ini sesuatu yang mirip dengan jawaban @GinkgoFr, tetapi tanpa masalah yang diidentifikasi oleh @Tino atau @DejayClayton, dan lebih kuat daripada set -o posixbit pintar @ DouglasLeeder :
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
Perbedaannya adalah bahwa solusi ini BERHENTI setelah laporan non-variabel pertama, misalnya fungsi pertama yang dilaporkan oleh set
BTW: Masalah "Tino" sudah terpecahkan. Meskipun POSIX dimatikan dan fungsi dilaporkan oleh set, sed ...porsi solusi hanya memungkinkan laporan variabel melalui (misalnya VAR=VALUEbaris). Secara khusus, A2tidak tidak spuriously membuatnya menjadi output.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
DAN: Masalah "DejayClayton" telah terpecahkan (baris baru yang disematkan dalam nilai variabel tidak mengganggu keluaran - masing-masing VAR=VALUEmendapatkan satu baris keluaran):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
CATATAN: Solusi yang disediakan oleh @DouglasLeeder mengalami masalah "DejayClayton" (nilai dengan baris baru yang disematkan). Di bawah ini, A1salah dan A2seharusnya tidak ditampilkan sama sekali.
$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999
AKHIRNYA: Menurut saya versi bashmasalahnya, tapi mungkin saja. Saya melakukan pengujian / pengembangan saya yang satu ini:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: Mengingat beberapa tanggapan lain untuk OP, saya <100% yakin bahwa set selalu mengubah baris baru dalam nilai \n, yang mana solusi ini bergantung untuk menghindari masalah "DejayClayton". Mungkin itu perilaku modern? Atau variasi waktu kompilasi? Atau pengaturan set -oatau shoptopsi? Jika Anda mengetahui variasi seperti itu, silakan tambahkan komentar ...
Dari perspektif keamanan, baik @ akostadinov ini jawaban atau @ JuvenXu ini jawabannya adalah lebih baik untuk mengandalkan output terstruktur dari setperintah, karena lubang keamanan potensial berikut:
#!/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
Fungsi di atas doLogicdigunakan setuntuk memeriksa keberadaan variabel PS1untuk menentukan apakah skrip itu interaktif atau tidak (tidak masalah apakah ini cara terbaik untuk mencapai tujuan itu; ini hanya sebuah contoh.)
Namun, keluaran dari settidak terstruktur, yang berarti bahwa variabel apa pun yang berisi baris baru dapat mencemari hasil secara total.
Ini, tentu saja, merupakan risiko keamanan potensial. Sebagai gantinya, gunakan dukungan Bash untuk perluasan nama variabel tidak langsung, atau compgen -v.
Coba ini: set | egrep "^\w+="(dengan atau tanpa | lesspemipaan)
Solusi yang diusulkan pertama ( set -o posix ; set ) | less,, berfungsi tetapi memiliki kekurangan: ia mentransmisikan kode kontrol ke terminal, sehingga tidak ditampilkan dengan benar. Jadi misalnya, jika ada (kemungkinan) suatu IFS=$' \t\n'variabel, kita dapat melihat:
IFS='
'
…sebagai gantinya.
egrepSolusi saya menampilkan ini (dan akhirnya yang serupa lainnya) dengan benar.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A tampilan yang salahA=B" -> Gagal!
Saya mungkin telah mencuri jawabannya beberapa waktu yang lalu ... toh sedikit berbeda sebagai fungsi:
##
# 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"
}
Cara sederhana untuk melakukannya adalah dengan menggunakan mode ketat bash dengan menyetel variabel lingkungan sistem sebelum menjalankan skrip Anda dan menggunakan diff untuk hanya mengurutkan skrip Anda:
# 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
Sekarang Anda dapat mengambil variabel dari skrip Anda di /tmp/script_vars.log. Atau setidaknya sesuatu berdasarkan itu!
Sedikit terlambat ke pesta, tapi inilah saran lainnya:
#!/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'
Baris perintah pipa diff + sed mengeluarkan semua variabel yang ditentukan skrip dalam format yang diinginkan (seperti yang ditentukan dalam posting OP):
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
-o posixsekarang diff hanya akan berisi variabel.