2012-02-09 33 views
21

Giả sử tôi có tệp tập lệnh bash config.sh. Nó có nghĩa là được source'd bởi các kịch bản khác và các biến được định nghĩa được sử dụng như là tùy biến của các kịch bản cấp cao hơn.bash: xác định biến tập tin cục bộ vô hình để tìm kiếm mã script

Vấn đề là, nếu config.sh có biến tạm thời và tên xung đột với biến tập lệnh cấp cao hơn, nó sẽ phá vỡ biến cấp cao hơn.

config.sh:

TMP1=abc 
CONFIG_INPUT_DIR="$TMP1"/in 
CONFIG_OUTPUT_DIR="$TMP1"/out 

thượng cấp kịch bản:

TMP1=def 
source config.sh 
echo $TMP1 

Các echo in cuối cùng abc, không def.

Giải pháp 1

giải pháp hiện tại của tôi là để nối thêm một chuỗi ngẫu nhiên để tên biến tạm thời để làm cho nó gần như không thể xung đột. ví dụ:

TMP1_vFc9Uiew=abc 
CONFIG_INPUT_DIR="$TMP1_vFc9Uiew"/in 
CONFIG_OUTPUT_DIR="$TMP1_vFc9Uiew"/out 
unset TMP1_vFc9Uiew 

gây đau đớn và làm cho mã khó đọc, ngoài việc không hoàn hảo.

Giải pháp 2 sử dụng local từ khóa

Sau khi một số tìm kiếm, tôi đã đến để nhận biết local từ khóa. Nhưng khi tôi chỉ cần khai báo TMP1local, bash khiếu nại rằng config.sh: line 1: local: can only be used in a function.

Vì vậy, giải pháp của tôi khác là kèm theo toàn bộ kịch bản cấu hình như một chức năng:

function config_func_rZ0Yqkpm() { 
    local TMP1=abc 
    CONFIG_INPUT_DIR="$TMP1"/in 
    CONFIG_OUTPUT_DIR="$TMP1"/out 
} 
config_func_rZ0Yqkpm 
unset config_func_rZ0Yqkpm 

đó là tốt hơn so với giải pháp trước đó trong khả năng bảo trì và khả năng đọc, nhưng có một số khả năng xung đột cũng như giải pháp 1.

Câu hỏi

Tôi muốn biết giải pháp mạnh mẽ và thông minh hơn mà không có bất kỳ khả năng xung đột nào.

Cảm ơn.

Trả lời

4

Bí quyết tôi đã học được từ tiện ích keychain đang sử dụng một chương trình để tạo tệp source có thể chứa chỉ các biến mà bạn muốn xuất từ ​​chương trình của mình. Bạn có thể sửa đổi kịch bản của bạn echo các biến bạn muốn thiết lập và sau đó nguồn các đầu ra từ chương trình của bạn:

$ echo $FOO 

$ source <(echo FOO=bar) 
$ echo $FOO 
bar 
$ 

tôi đã sử dụng echo FOO=bar để mô phỏng kịch bản lớn hơn; chương trình của bạn có thể tham gia nhiều hơn. Phần quan trọng là bạn phải sửa đổi chương trình của bạn để xuất các biến và giá trị bạn muốn đặt, thay vì chỉ thiết lập chúng. Điều này cho phép bạn quyết định biến nào sẽ hiển thị và biến nào giữ riêng tư với chi phí của một quá trình shell khác.

+0

'ssh-agent' sử dụng một kỹ thuật tương tự, với các tùy chọn' -c' và '-s'. – jjlin

+0

@jjlin: Cảm ơn bạn! Tôi nghĩ rằng 'keychain' không chính xác là nơi tôi nhìn thấy nó đầu tiên, nhưng nó là nơi đầu tiên tôi tìm thấy tài liệu. :) Buồn cười, nó đang ngồi ngay tại cửa sổ mở trong trang 'ssh-agent' ... – sarnold

+0

@sarnold: Tuyệt vời, cảm ơn bạn! Tôi sẽ thử kỹ thuật này. – niboshi

0

Hai phương pháp thông thường để tạo tên tệp duy nhất là sử dụng hàm mktemp, được đảm bảo tạo tên tệp duy nhất hoặc để nhúng PID vào tên tệp. PID sẽ được đặt trong biến '$$'.

+0

Vấn đề là không phải xây dựng tên tập tin duy nhất nhưng names_ _variable độc ​​đáo. (Hoặc, tốt hơn, một số cơ chế phạm vi.) – sarnold

+0

Gotcha. ... Tôi đã bị nhầm lẫn bởi việc sử dụng '$ CONFIG_INPUT_DIR' ... cú pháp, nó là một biến, ngữ nghĩa, nó là một thư mục. –

6

Bạn có thể tránh được các biến và chức năng sử dụng trong config.sh để giữ giá trị của bạn:

get_dirname() { echo "abc"; } 
CONFIG_INPUT_DIR="$(get_dirname)/in" 
CONFIG_OUTPUT_DIR="$(get_dirname)/out" 
unset -f get_dirname 

Nếu bạn vẫn lo ngại về tên va chạm cho các chức năng, điều này không thực sự giúp bạn.

4

Các "ssh-agent" phương pháp:

config.sh

#!/bin/bash 
TMP=abc 
printf "CONFIG_INPUT_DIR=%s/in" "$TMP" 
printf "CONFIG_OUTPUT_DIR=%s/out" "$TMP" 

chương trình chính:

TMP1=def 
eval $(config.sh) 
echo $TMP1 
Các vấn đề liên quan