Cách tốt nhất để biến các biến cục bộ trong tập lệnh bash nguồn?


7

Tôi có một tập lệnh bash tạo báo cáo về tiến trình của một số công việc chạy dài trên máy. Về cơ bản, tập lệnh cha mẹ này lặp lại thông qua một danh sách các tập lệnh con (gọi tất cả chúng bằng source). Các tập lệnh con được dự kiến ​​sẽ đặt một vài biến cụ thể, tập lệnh cha sẽ sử dụng.

Hôm nay, tôi phát hiện ra một lỗi trong đó, một biến được đặt bởi tập lệnh con đầu tiên vô tình được sử dụng bởi tập lệnh con thứ hai, gây ra đầu ra không chính xác. Có cách nào sạch để ngăn chặn các loại lỗi này xảy ra không?

Về cơ bản, khi tôi sourcelà một tập lệnh con, có một vài biến cụ thể mà tôi muốn tiếp tục quay lại tập lệnh cha. Tập lệnh cha của tôi đặt lại các biến cụ thể này trước sourcemỗi tập lệnh con mới, vì vậy không có vấn đề gì với chúng. Tuy nhiên, một số tập lệnh con có thể có các biến tùy ý bổ sung mà nó sử dụng cục bộ không nên tồn tại trở lại tập lệnh mẹ.

Rõ ràng là tôi có thể tự hủy bỏ từng phần này ở phần cuối của tập lệnh con, nhưng chúng có vẻ dễ bị lỗi nếu tôi quên. Có cách nào phù hợp hơn để tìm nguồn cung cấp một tập lệnh và chỉ có một số biến nhất định tồn tại trong tập lệnh được gọi sourcekhông?

chỉnh sửa: Để rõ ràng, đây là một phiên bản ngu ngốc của tập lệnh gốc của tôi:

echo "<html><body><h1>My jobs</h1>"

FILES=~/confs/*.sh
for f in $FILES; do
  # reset variables
  name="Unnamed job"
  secsSinceActive="Unknown"
  statusText="Unknown"

  # run the script that checks on the job
  source "$f"

  # print bit of report
  echo "<h3>$name</h3>"
  echo "<p>Last active: $secsSinceActive seconds ago</p>"
  echo "<p>Status: $statusText</p>"

echo "</body></html>"

Và đây là một trong những kịch bản con có thể trông như thế nào:

name="My awesome job"

nowTime=`expr $(date +%s) `
lastActiveTime=`expr $(date +%s -r ~/blah.log)`
secsSinceActive=`expr $nowTime - $lastActiveTime`

currentRaw=$(cat ~/blah.log | grep "Progress" | tail -n 1)
if [ -z "$currentRaw" ]; then
  statusText="Not running"
else
  statusText="In progress"
fi

Các biến $ name, $ secsSinceActive và $ statusText cần phải tồn tại trở lại tập lệnh cha, nhưng tất cả các biến khác sẽ biến mất khi tập lệnh con kết thúc.


Bạn có thể gọi sourcevà kiểm tra các bộ phận cho một subshell để chúng thực sự không ảnh hưởng đến cha mẹ vĩnh viễn?
Eric Renouf

Nếu tôi đã làm điều đó, làm thế nào tôi có thể giữ cho các biến cụ thể mà tôi làm muốn kéo dài từ đứa trẻ để phụ huynh?
Hayden Schiff

@ oxyguy3 Nếu bạn không làm phiền họ, tôi nghĩ rằng bạn không thực sự cần họ kiên trì, có lẽ vẫn còn những người khác
Eric Renouf

@EricRenouf Tôi đã thêm một số mã ví dụ cho rõ ràng; Tôi cần một số biến cụ thể để tồn tại, nhưng bất kỳ biến nào nằm ngoài danh sách các biến được phê duyệt cụ thể của tôi đều cần phải chết.
Hayden Schiff

2
Đây là một cạm bẫy tinh túy của việc sử dụng các biến toàn cục trong lập trình. Bạn nên sử dụng một cơ chế mạnh mẽ hơn cho việc này, chẳng hạn như phân tích các giá trị từ đầu ra của mỗi quy trình con hoặc sử dụng các tệp tạm thời để lưu trữ chúng.
goldilocks

Câu trả lời:


9

Gói toàn bộ tập lệnh mà bạn muốn nguồn vào một hàm, thêm cục bộ trước các khai báo bạn muốn chỉ sử dụng trong hàm và gọi hàm ở cuối tập lệnh.

func () {
    local name="My awesome job"

    nowTime=`expr $(date +%s) `
    lastActiveTime=`expr $(date +%s -r ~/blah.log)`
    local secsSinceActive=`expr $nowTime - $lastActiveTime`

    currentRaw=$(cat ~/blah.log | grep "Progress" | tail -n 1)
    if [ -z "$currentRaw" ]; then
      local statusText="Not running"
    else
      local statusText="In progress"
    fi
}
func

1
Giải pháp tốt nhất imo, nhưng đối với những người đọc câu trả lời này, hãy nhớ rằng func()chức năng trên sẽ vẫn hiện diện trong phạm vi cha mẹ và làm ô nhiễm nó; để tránh những cái tên mâu thuẫn, giải pháp tốt nhất mà tôi biết là đặt cho nó một cái tên xấu xí, đại loại như___this_main___()
yolenoyer

1
Để tự dọn dẹp chức năng, bạn có thể sử dụng unset -f funcngay sau khi gọi nó.
JWD

-1

Tôi tin rằng cú pháp để tạo một biến cục bộ trong bash là:

local variable_name=

Tôi biết điều này hoạt động cho các chức năng và không chắc nó hoạt động như thế nào với nhiều tập lệnh.


1
Dường như nó chỉ có thể được sử dụng cho các chức năng; Tôi gặp lỗi:local: can only be used in a function
Hayden Schiff
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.