Câu trả lời:
set
sẽ xuất ra các biến, tiếc là nó cũng sẽ xuất ra các hàm được định nghĩa.
May mắn thay, chế độ POSIX chỉ xuất ra các biến:
( set -o posix ; set ) | less
Đường ống đến less
hoặc chuyển hướng đến nơi bạn muốn các tùy chọn.
Vì vậy, để lấy các biến được khai báo chỉ trong 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
(Hoặc ít nhất là một cái gì đó dựa trên :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;
. Điều này cũng sẽ xuất ra các vars ở định dạng sẵn sàng để lưu. Danh sách này sẽ bao gồm các biến kịch bản thay đổi (nó phụ thuộc cho dù đây là mong muốn)
source
, bạn sẽ có thể làm như vậy với đầu ra của declare -p
.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
Nó liệt kê tất cả các biến bao gồm các biến cục bộ. Tôi đã học được điều đó từ Nhận danh sách các biến có tên khớp với một mẫu nhất định và sử dụng nó trong tập lệnh của tôi .
compgen -v
cũng liệt kê các biến toàn cục chưa được đặt cục bộ. Không chắc đó là lỗi lâu đời hay hành vi mong muốn.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Điều này phải in tất cả các tên biến shell. Bạn có thể nhận được một danh sách trước và sau khi tìm nguồn cung cấp tệp của mình giống như với "set" để khác với các biến mới (như được giải thích trong các câu trả lời khác). Nhưng hãy nhớ rằng việc lọc như vậy với diff có thể lọc ra một số biến mà bạn cần nhưng đã có trước khi tìm nguồn cung cấp tệp của bạn.
Trong trường hợp của bạn, nếu bạn biết tên biến của mình bắt đầu bằng "VARIABLE", thì bạn có thể tạo nguồn tập lệnh của mình và thực hiện:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
CẬP NHẬT: Đối với giải pháp BASH thuần túy (không sử dụng lệnh bên ngoài):
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})"
Dựa trên một số câu trả lời ở trên, điều này phù hợp với tôi:
before=$(set -o posix; set | sort);
tệp nguồn :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Nếu bạn có thể xử lý hậu kỳ, (như đã đề cập), bạn có thể chỉ cần thực hiện set
lệnh gọi ở đầu và cuối tập lệnh của mình (mỗi tập lệnh với một tệp khác nhau) và thực hiện sự khác biệt trên hai tệp. Nhận ra rằng điều này sẽ vẫn chứa một số tiếng ồn.
Bạn cũng có thể làm điều này theo chương trình. Để giới hạn đầu ra chỉ trong phạm vi hiện tại của bạn, bạn sẽ phải triển khai trình bao bọc để tạo biến. Ví dụ
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
Kết quả nào
VAR1=abc
VAR2=bcd
VAR3=cde
Đây là một cái gì đó tương tự với câu trả lời @GinkgoFr, nhưng không có vấn đề được xác định bởi @Tino hoặc @DejayClayton và mạnh mẽ hơn set -o posix
một chút thông minh của @ DouglasLeeder :
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
Sự khác biệt là giải pháp này BƯỚC sau báo cáo không biến đầu tiên, ví dụ: hàm đầu tiên được báo cáo bởi set
BTW: Vấn đề "Tino" đã được giải quyết. Mặc dù POSIX bị tắt và các chức năng được báo cáo set
, sed ...
phần của giải pháp chỉ cho phép các báo cáo thay đổi thông qua (ví dụ: VAR=VALUE
dòng). Đặc biệt, A2
không không spuriously làm cho nó vào đầu ra.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
VÀ: Vấn đề "DejayClayton" đã được giải quyết (các dòng mới được nhúng trong các giá trị biến không làm gián đoạn đầu ra - mỗi dòng VAR=VALUE
nhận được một dòng đầu ra):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
LƯU Ý: Giải pháp do @DouglasLeeder cung cấp gặp phải sự cố "DejayClayton" (các giá trị có dòng mới được nhúng). Dưới đây, A1
là sai và A2
không nên hiển thị ở tất cả.
$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999
CUỐI CÙNG: Tôi không nghĩ phiên bản của bash
vấn đề, nhưng nó có thể xảy ra. Tôi đã thực hiện thử nghiệm / phát triển của mình trên cái này:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: Với một số phản hồi khác cho OP, tôi chắc chắn <100% set
luôn chuyển đổi các dòng mới trong giá trị thành \n
, mà giải pháp này dựa vào để tránh sự cố "DejayClayton". Có lẽ đó là một hành vi hiện đại? Hay một biến thể thời gian biên dịch? Hoặc một set -o
hoặc shopt
thiết lập tùy chọn? Nếu bạn biết về các biến thể như vậy, vui lòng thêm một bình luận ...
Từ góc độ an ninh, hoặc @ của akostadinov câu trả lời hoặc @ JuvenXu của câu trả lời là thích hợp hơn để dựa vào đầu ra không có cấu trúc của set
lệnh, do lỗ hổng bảo mật tiềm năng sau đây:
#!/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
Hàm trên doLogic
sử dụng set
để kiểm tra sự hiện diện của biến PS1
để xác định xem script có tương tác hay không (đừng bận tâm nếu đây là cách tốt nhất để thực hiện mục tiêu đó; đây chỉ là một ví dụ).
Tuy nhiên, đầu ra của set
là không có cấu trúc, có nghĩa là bất kỳ biến nào chứa một dòng mới đều có thể làm ô nhiễm hoàn toàn kết quả.
Tất nhiên, đây là một rủi ro bảo mật tiềm ẩn. Thay vào đó, hãy sử dụng sự hỗ trợ của Bash để mở rộng tên biến gián tiếp hoặc compgen -v
.
Hãy thử điều này: set | egrep "^\w+="
(có hoặc không có | less
đường ống)
Giải pháp được đề xuất đầu tiên ( set -o posix ; set ) | less
, hoạt động nhưng có một nhược điểm: nó truyền các mã điều khiển đến thiết bị đầu cuối, vì vậy chúng không được hiển thị đúng cách. Vì vậy, ví dụ, nếu có (khả năng xảy ra) một IFS=$' \t\n'
biến, chúng ta có thể thấy:
IFS='
'
…thay thế.
egrep
Giải pháp của tôi hiển thị điều này (và cuối cùng là các giải pháp tương tự khác) đúng cách.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A
hiển thị sai đơn giảnA=B"
-> Không thành công!
Tôi có thể đã đánh cắp câu trả lời trong khi trước đây ... dù sao thì hơi khác với tư cách là một 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"
}
Cách đơn giản để thực hiện việc này là sử dụng chế độ nghiêm ngặt bash bằng cách đặt các biến môi trường hệ thống trước khi chạy tập lệnh của bạn và sử dụng khác biệt để chỉ sắp xếp các biến trong tập lệnh của bạn:
# 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
Bây giờ bạn có thể truy xuất các biến của tập lệnh của mình trong /tmp/script_vars.log. Hoặc ít nhất là một cái gì đó dựa trên đó!
Đến bữa tiệc hơi muộn, nhưng đây là một gợi ý khác:
#!/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'
Dòng lệnh đường ống diff + sed xuất ra tất cả các biến do tập lệnh xác định ở định dạng mong muốn (như được chỉ định trong bài đăng của OP):
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
-o posix
bây giờ một khác biệt sẽ chỉ chứa các biến.