Làm thế nào để sửa đổi một biến toàn cục trong một hàm trong bash?


104

Tôi đang làm việc với cái này:

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

Tôi có một kịch bản như sau:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

test1 
echo "$e"

Trả về:

hello
4

Nhưng nếu tôi gán kết quả của hàm cho một biến, thì biến toàn cục esẽ không được sửa đổi:

#!/bin/bash

e=2

function test1() {
  e=4
  echo "hello"
}

ret=$(test1)

echo "$ret"
echo "$e"

Lợi nhuận:

hello
2

Tôi đã nghe nói về việc sử dụng eval trong trường hợp này, vì vậy tôi đã làm điều này trong test1:

eval 'e=4'

Nhưng cùng một kết quả.

Bạn có thể giải thích cho tôi lý do tại sao nó không được sửa đổi? Làm cách nào để lưu lại tiếng vang của test1hàm retvà sửa đổi cả biến toàn cục?


Bạn có cần chào lại không? Bạn chỉ có thể gọi lại $ e để nó quay trở lại. Hoặc lặp lại mọi thứ bạn muốn và sau đó phân tích cú pháp kết quả?

Câu trả lời:


98

Khi bạn sử dụng thay thế lệnh (tức là $(...)cấu trúc), bạn đang tạo một vỏ con. Các vỏ con kế thừa các biến từ vỏ mẹ của chúng, nhưng điều này chỉ hoạt động theo một cách - một vỏ con không thể sửa đổi môi trường của vỏ mẹ của nó. Biến của bạn eđược đặt trong vỏ con, nhưng không được đặt trong vỏ mẹ. Có hai cách để chuyển các giá trị từ vỏ con đến vỏ mẹ của nó. Đầu tiên, bạn có thể xuất một thứ gì đó ra stdout, sau đó nắm bắt nó bằng một lệnh thay thế:

myfunc() {
    echo "Hello"
}

var="$(myfunc)"

echo "$var"

Cung cấp:

Hello

Đối với giá trị số từ 0-255, bạn có thể sử dụng returnđể chuyển số làm trạng thái thoát:

mysecondfunc() {
    echo "Hello"
    return 4
}

var="$(mysecondfunc)"
num_var=$?

echo "$var - num is $num_var"

Cung cấp:

Hello - num is 4

Cảm ơn vì điểm này, nhưng tôi phải trả về một mảng chuỗi và trong hàm tôi phải thêm các phần tử vào hai mảng chuỗi toàn cục.
harrison

3
Bạn nhận ra rằng nếu bạn chỉ chạy hàm mà không gán nó cho một biến thì tất cả các biến toàn cục bên trong nó sẽ cập nhật. Thay vì trả về một mảng chuỗi, tại sao bạn không cập nhật mảng chuỗi trong hàm rồi gán nó cho một biến khác sau khi hàm kết thúc?

@JohnDoe: Bạn không thể trả về "mảng chuỗi" từ một hàm. Tất cả những gì bạn có thể làm là in một chuỗi. Tuy nhiên, bạn có thể làm điều gì đó như sau:setarray() { declare -ag "$1=(a b c)"; }
rici

34

Điều này cần bash 4.1 nếu bạn sử dụng {fd}hoặc local -n.

Phần còn lại sẽ hoạt động trong bash 3.x Tôi hy vọng. Tôi không hoàn toàn chắc chắn do printf %q- đây có thể là một tính năng bash 4.

Tóm lược

Ví dụ của bạn có thể được sửa đổi như sau để lưu trữ hiệu ứng mong muốn:

# Add following 4 lines:
_passback() { while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
passback() { _passback "$@" "$?"; }
_capture() { { out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)"; }
capture() { eval "$(_capture "$@")"; }

e=2

# Add following line, called "Annotation"
function test1_() { passback e; }
function test1() {
  e=4
  echo "hello"
}

# Change following line to:
capture ret test1 

echo "$ret"
echo "$e"

in như mong muốn:

hello
4

Lưu ý rằng giải pháp này:

  • Hoạt động cho e=1000, quá.
  • Bảo quản $?nếu bạn cần$?

Những tác động xấu duy nhất là:

  • Nó cần một hiện đại bash.
  • Nó fork thường xuyên hơn.
  • Nó cần chú thích (được đặt tên theo chức năng của bạn, với một phần bổ sung _)
  • Nó hy sinh bộ mô tả tệp 3.
    • Bạn có thể thay đổi nó thành FD khác nếu bạn cần.
      • Trong _capturechỉ cần thay thế tất cả các lần xuất hiện của 3với một số (cao hơn).

Phần sau (khá dài, rất tiếc vì điều đó) hy vọng sẽ giải thích, cách gắn công thức này vào các tập lệnh khác.

Vấn đề

d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
d1=$(d)
d2=$(d)
d3=$(d)
d4=$(d)
echo $x $d1 $d2 $d3 $d4

đầu ra

0 20171129-123521 20171129-123521 20171129-123521 20171129-123521

trong khi đầu ra mong muốn là

4 20171129-123521 20171129-123521 20171129-123521 20171129-123521

Nguyên nhân của vấn đề

Các biến Shell (hay nói chung là môi trường) được chuyển từ các quy trình mẹ sang các quy trình con, nhưng không phải ngược lại.

Nếu bạn thực hiện thu thập dữ liệu đầu ra, điều này thường được chạy trong một vỏ con, do đó, việc chuyển lại các biến trở lại rất khó khăn.

Một số thậm chí nói với bạn, rằng nó không thể sửa chữa được. Điều này là sai, nhưng nó là một vấn đề khó giải được biết từ lâu.

Có một số cách về cách giải quyết nó tốt nhất, điều này phụ thuộc vào nhu cầu của bạn.

Đây là hướng dẫn từng bước về cách thực hiện.

Chuyển lại các biến vào shell cha

Có một cách để chuyển lại các biến cho một shell gốc. Tuy nhiên đây là một con đường nguy hiểm, bởi vì điều này sử dụng eval. Nếu làm không đúng cách, bạn có nguy cơ gặp nhiều điều ác. Nhưng nếu được thực hiện đúng cách, điều này hoàn toàn an toàn, miễn là không có lỗi nào trong đó bash.

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }

d() { let x++; d=$(date +%Y%m%d-%H%M%S); _passback x d; }

x=0
eval `d`
d1=$d
eval `d`
d2=$d
eval `d`
d3=$d
eval `d`
d4=$d
echo $x $d1 $d2 $d3 $d4

bản in

4 20171129-124945 20171129-124945 20171129-124945 20171129-124945

Lưu ý rằng điều này cũng có hiệu quả đối với những thứ nguy hiểm:

danger() { danger="$*"; passback danger; }
eval `danger '; /bin/echo *'`
echo "$danger"

bản in

; /bin/echo *

Điều này là do printf '%q', trích dẫn mọi thứ như vậy, mà bạn có thể sử dụng lại nó trong ngữ cảnh shell một cách an toàn.

Nhưng đây là một nỗi đau trong ..

Điều này không chỉ trông xấu xí mà còn phải đánh máy nhiều nên dễ bị lỗi. Chỉ một sai lầm duy nhất và bạn phải chịu đựng, phải không?

Chà, chúng tôi đang ở cấp độ vỏ, vì vậy bạn có thể cải thiện nó. Chỉ cần nghĩ về một giao diện bạn muốn xem và sau đó bạn có thể triển khai nó.

Tăng cường, cách shell xử lý mọi thứ

Hãy quay lại một bước và suy nghĩ về một số API cho phép chúng ta dễ dàng thể hiện những gì chúng ta muốn làm.

Chà, chúng ta muốn làm gì với d()hàm?

Chúng tôi muốn nắm bắt đầu ra thành một biến. OK, sau đó hãy triển khai một API cho chính xác điều này:

# This needs a modern bash 4.3 (see "help declare" if "-n" is present,
# we get rid of it below anyway).
: capture VARIABLE command args..
capture()
{
local -n output="$1"
shift
output="$("$@")"
}

Bây giờ, thay vì viết

d1=$(d)

chúng tôi có thể viết

capture d1 d

Chà, điều này có vẻ như chúng ta không thay đổi nhiều, vì một lần nữa, các biến không được chuyển trở lại từ dtrình bao mẹ và chúng ta cần phải nhập thêm một chút.

Tuy nhiên, bây giờ chúng ta có thể ném toàn bộ sức mạnh của shell vào nó, vì nó được gói gọn trong một hàm.

Hãy nghĩ về một giao diện dễ sử dụng lại

Điều thứ hai là chúng tôi muốn trở nên KHÔ (Không lặp lại chính mình). Vì vậy, chúng tôi chắc chắn không muốn nhập những thứ như

x=0
capture1 x d1 d
capture1 x d2 d
capture1 x d3 d
capture1 x d4 d
echo $x $d1 $d2 $d3 $d4

xđây không chỉ thừa, nó dễ bị lỗi luôn lặp lại trong ngữ cảnh chính xác. Điều gì sẽ xảy ra nếu bạn sử dụng nó 1000 lần trong một script và sau đó thêm một biến? Bạn chắc chắn không muốn thay đổi tất cả 1000 vị trí nơi một cuộc gọi đếnd liên quan đến .

Vì vậy, hãy bỏ xđi, để chúng ta có thể viết:

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }

d() { let x++; output=$(date +%Y%m%d-%H%M%S); _passback output x; }

xcapture() { local -n output="$1"; eval "$("${@:2}")"; }

x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4

đầu ra

4 20171129-132414 20171129-132414 20171129-132414 20171129-132414

Điều này đã trông rất tốt. (Nhưng vẫn có local -ncái không hoạt động trong oder chung bash3.x)

Tránh thay đổi d()

Giải pháp cuối cùng có một số sai sót lớn:

  • d() cần được thay đổi
  • Nó cần phải sử dụng một số chi tiết bên trong xcaptuređể vượt qua đầu ra.
    • Lưu ý rằng bóng đổ này (đốt cháy) một biến được đặt tên output, vì vậy chúng ta không bao giờ có thể chuyển lại biến này.
  • Nó cần hợp tác với _passback

Chúng ta có thể loại bỏ điều này không?

Tất nhiên, chúng tôi có thể! Chúng tôi đang ở trong một cái vỏ, vì vậy có mọi thứ chúng tôi cần để hoàn thành việc này.

Nếu bạn nhìn kỹ hơn một chút vào cuộc gọi, evalbạn có thể thấy rằng chúng tôi có 100% quyền kiểm soát tại vị trí này. "Bên trong", evalchúng ta nằm trong một vỏ con, vì vậy chúng ta có thể làm mọi thứ mình muốn mà không sợ làm điều gì đó xấu với vỏ mẹ.

Vâng, tốt, vì vậy hãy thêm một trình bao bọc khác, bây giờ trực tiếp bên trong eval:

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
# !DO NOT USE!
_xcapture() { "${@:2}" > >(printf "%q=%q;" "$1" "$(cat)"); _passback x; }  # !DO NOT USE!
# !DO NOT USE!
xcapture() { eval "$(_xcapture "$@")"; }

d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4

bản in

4 20171129-132414 20171129-132414 20171129-132414 20171129-132414                                                    

Tuy nhiên, điều này, một lần nữa, có một số nhược điểm lớn:

  • Các !DO NOT USE!điểm đánh dấu ở đó, bởi vì có một điều kiện đường đua rất tồi tệ, bạn không thể nhìn thấy dễ dàng:
    • Đây >(printf ..)là một công việc nền tảng. Vì vậy, nó có thể vẫn thực thi trong khi _passback xđang chạy.
    • Bạn có thể tự nhìn thấy điều này nếu bạn thêm sleep 1;trước printfhoặc _passback. _xcapture a d; echosau đó đầu ra xhoặc ađầu tiên, tương ứng.
  • Không _passback xnên là một phần của_xcapture , vì điều này gây khó khăn cho việc sử dụng lại công thức đó.
  • Ngoài ra, chúng tôi có một số ngã ba chưa được thực hiện ở đây (sự $(cat)), nhưng vì giải pháp này là !DO NOT USE!tôi đã đi con đường ngắn nhất.

Tuy nhiên, điều này cho thấy rằng chúng ta có thể làm được điều đó mà không cần sửa đổi d()(và không cầnlocal -n )!

Xin lưu ý rằng chúng tôi không nhất thiết cần _xcapturechút nào, vì chúng tôi có thể đã viết mọi nội dung ngay trongeval .

Tuy nhiên làm điều này thường không dễ đọc. Và nếu bạn quay lại kịch bản của mình sau một vài năm, bạn có thể muốn đọc lại nó mà không gặp nhiều khó khăn.

Khắc phục cuộc đua

Bây giờ chúng ta hãy sửa điều kiện cuộc đua.

Bí quyết có thể là đợi cho đến khi printfnó đóng STDOUT, và sau đó xuất ra x.

Có nhiều cách để lưu trữ cái này:

  • Bạn không thể sử dụng các đường ống shell, vì các đường ống chạy trong các quy trình khác nhau.
  • Người ta có thể sử dụng các tệp tạm thời,
  • hoặc một cái gì đó như một tập tin khóa hoặc một năm. Điều này cho phép chờ khóa hoặc năm mươi,
  • hoặc các kênh khác nhau, để xuất thông tin, và sau đó lắp ráp đầu ra theo một số trình tự đúng.

Theo đường dẫn cuối cùng có thể trông như thế nào (lưu ý rằng nó là đường printfcuối cùng vì nó hoạt động tốt hơn ở đây):

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }

_xcapture() { { printf "%q=%q;" "$1" "$("${@:2}" 3<&-; _passback x >&3)"; } 3>&1; }

xcapture() { eval "$(_xcapture "$@")"; }

d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
xcapture d1 d
xcapture d2 d
xcapture d3 d
xcapture d4 d
echo $x $d1 $d2 $d3 $d4

đầu ra

4 20171129-144845 20171129-144845 20171129-144845 20171129-144845

Tại sao điều này là chính xác?

  • _passback x trực tiếp nói chuyện với STDOUT.
  • Tuy nhiên, vì STDOUT cần được nắm bắt trong lệnh bên trong, trước tiên chúng tôi "lưu" nó vào FD3 (tất nhiên bạn có thể sử dụng những người khác) với '3> & 1' và sau đó sử dụng lại với >&3.
  • Các $("${@:2}" 3<&-; _passback x >&3)kết thúc sau _passback, khi vỏ con đóng STDOUT.
  • Vì vậy, printfkhông thể xảy ra trước _passback, bất kể _passbackmất bao lâu .
  • Lưu ý rằng printflệnh không được thực thi trước khi dòng lệnh hoàn chỉnh được lắp ráp, vì vậy chúng ta không thể thấy các đồ tạo tác từ đó printf, cách printfthực hiện một cách độc lập .

Do đó đầu tiên _passbackthực thi, sau đó printf.

Điều này giải quyết cuộc đua, hy sinh một bộ mô tả tệp cố định 3. Tất nhiên, bạn có thể chọn một bộ mô tả tệp khác trong trường hợp FD3 không miễn phí trong shellcript của bạn.

Cũng xin lưu ý rằng 3<&-điều này bảo vệ FD3 được chuyển đến hàm.

Làm cho nó chung chung hơn

_capture chứa các bộ phận, thuộc về d() , xấu, từ góc độ khả năng tái sử dụng. Làm thế nào để giải quyết điều này?

Vâng, hãy làm điều đó theo cách khác biệt bằng cách giới thiệu một thứ nữa, một hàm bổ sung, phải trả về những thứ phù hợp, được đặt tên theo hàm ban đầu với _đính kèm.

Hàm này được gọi sau hàm thực và có thể làm tăng thêm mọi thứ. Bằng cách này, điều này có thể được đọc như một số chú thích, vì vậy nó rất dễ đọc:

_passback() { while [ 0 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; }
_capture() { { printf "%q=%q;" "$1" "$("${@:2}" 3<&-; "$2_" >&3)"; } 3>&1; }
capture() { eval "$(_capture "$@")"; }

d_() { _passback x; }
d() { let x++; date +%Y%m%d-%H%M%S; }

x=0
capture d1 d
capture d2 d
capture d3 d
capture d4 d
echo $x $d1 $d2 $d3 $d4

vẫn in

4 20171129-151954 20171129-151954 20171129-151954 20171129-151954

Cho phép truy cập vào mã trả lại

Chỉ còn thiếu một chút:

v=$(fn)đặt $?thành những gì đã fntrả lại. Vì vậy, bạn có thể cũng muốn điều này. Tuy nhiên, nó cần một số điều chỉnh lớn hơn:

# This is all the interface you need.
# Remember, that this burns FD=3!
_passback() { while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
passback() { _passback "$@" "$?"; }
_capture() { { out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)"; }
capture() { eval "$(_capture "$@")"; }

# Here is your function, annotated with which sideffects it has.
fails_() { passback x y; }
fails() { x=$1; y=69; echo FAIL; return 23; }

# And now the code which uses it all
x=0
y=0
capture wtf fails 42
echo $? $x $y $wtf

bản in

23 42 69 FAIL

Vẫn còn rất nhiều chỗ để cải thiện

  • _passback() có thể được tách ra với passback() { set -- "$@" "$?"; while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }
  • _capture() có thể được loại bỏ với capture() { eval "$({ out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)")"; }

  • Giải pháp gây ô nhiễm bộ mô tả tệp (ở đây 3) bằng cách sử dụng nó trong nội bộ. Bạn cần ghi nhớ điều đó nếu tình cờ vượt qua FDs.
    Lưu ý rằng bash4.1 trở lên {fd}phải sử dụng một số FD không được sử dụng.
    (Có lẽ tôi sẽ thêm một giải pháp ở đây khi tôi xem xét.)
    Lưu ý rằng đây là lý do tại sao tôi sử dụng để đặt nó trong các chức năng riêng biệt như _capture, bởi vì việc nhồi nhét tất cả vào một dòng là có thể, nhưng khiến nó ngày càng khó đọc và khó hiểu

  • Có lẽ bạn cũng muốn nắm bắt STDERR của hàm được gọi. Hoặc bạn thậm chí muốn chuyển vào và chuyển ra nhiều hơn một bộ ký mã từ và đến các biến.
    Tôi chưa có giải pháp nào, tuy nhiên đây là một cách để bắt nhiều hơn một FD , vì vậy chúng ta cũng có thể trả lại các biến theo cách này.

Cũng đừng quên:

Điều này phải gọi một hàm shell, không phải một lệnh bên ngoài.

Không có cách nào dễ dàng để chuyển các biến môi trường ra khỏi các lệnh bên ngoài. ( LD_PRELOAD=Mặc dù với điều đó thì có thể!) Nhưng điều này sau đó là một cái gì đó hoàn toàn khác.

Những từ cuối

Đây không phải là giải pháp khả thi duy nhất. Đó là một ví dụ cho một giải pháp.

Như mọi khi bạn có nhiều cách để thể hiện mọi thứ trong vỏ. Vì vậy, hãy thoải mái cải thiện và tìm kiếm thứ gì đó tốt hơn.

Giải pháp được trình bày ở đây còn khá xa mới là hoàn hảo:

  • Nó gần như không phải testet ở tất cả, vì vậy xin vui lòng bỏ qua lỗi chính tả.
  • Có rất nhiều chỗ để cải thiện, xem ở trên.
  • Nó sử dụng nhiều tính năng từ hiện đại bash, vì vậy có lẽ khó có thể chuyển sang các shell khác.
  • Và có thể có một số điều kỳ quặc mà tôi chưa nghĩ đến.

Tuy nhiên, tôi nghĩ rằng nó khá dễ sử dụng:

  • Chỉ thêm 4 dòng "thư viện".
  • Chỉ thêm 1 dòng "chú thích" cho hàm shell của bạn.
  • Chỉ tạm thời hy sinh một bộ mô tả tệp.
  • Và mỗi bước phải dễ hiểu ngay cả nhiều năm sau đó.

2
bạn thật tuyệt vời
Eliran Malka

14

Có thể bạn có thể sử dụng một tệp, ghi vào tệp bên trong hàm, đọc từ tệp sau nó. Tôi đã thay đổi ethành một mảng. Trong ví dụ này, các khoảng trống được sử dụng làm dấu phân cách khi đọc lại mảng.

#!/bin/bash

declare -a e
e[0]="first"
e[1]="secondddd"

function test1 () {
 e[2]="third"
 e[1]="second"
 echo "${e[@]}" > /tmp/tempout
 echo hi
}

ret=$(test1)

echo "$ret"

read -r -a e < /tmp/tempout
echo "${e[@]}"
echo "${e[0]}"
echo "${e[1]}"
echo "${e[2]}"

Đầu ra:

hi
first second third
first
second
third

13

Bạn đang làm gì, bạn đang thực hiện test1

$(test1)

trong sub-shell (shell con) và Child shell không thể sửa đổi bất cứ thứ gì trong cha .

Bạn có thể tìm thấy nó trong sách hướng dẫn sử dụng bash

Vui lòng kiểm tra: Mọi thứ dẫn đến kết quả ở đây


7

Tôi đã gặp sự cố tương tự, khi tôi muốn tự động xóa các tệp tạm thời mà tôi đã tạo. Giải pháp mà tôi đưa ra không phải là sử dụng thay thế lệnh, mà là chuyển tên của biến, sẽ đưa kết quả cuối cùng vào hàm. Ví dụ

#! /bin/bash

remove_later=""
new_tmp_file() {
    file=$(mktemp)
    remove_later="$remove_later $file"
    eval $1=$file
}
remove_tmp_files() {
    rm $remove_later
}
trap remove_tmp_files EXIT

new_tmp_file tmpfile1
new_tmp_file tmpfile2

Vì vậy, trong trường hợp của bạn, đó sẽ là:

#!/bin/bash

e=2

function test1() {
  e=4
  eval $1="hello"
}

test1 ret

echo "$ret"
echo "$e"

Hoạt động và không có hạn chế về "giá trị trả lại".


1

Đó là vì thay thế lệnh được thực hiện trong một vỏ con, vì vậy trong khi vỏ con kế thừa các biến, các thay đổi đối với chúng sẽ bị mất khi kết thúc vỏ con.

Tham khảo :

Thay thế lệnh, các lệnh được nhóm với dấu ngoặc đơn và các lệnh không đồng bộ được gọi trong môi trường shell con là bản sao của môi trường shell


@JohnDoe Tôi không chắc là có thể. Bạn có thể phải suy nghĩ lại về thiết kế kịch bản của mình.
Một số lập trình viên dude

Ồ, nhưng tôi cần phải giả định một mảng toàn cục trong một hàm, nếu không, tôi sẽ phải lặp lại rất nhiều mã (lặp lại mã của hàm -30 dòng- 15 lần-một lần gọi-). Không còn cách nào khác, phải không?
harrison

1

Một giải pháp cho vấn đề này, mà không cần phải giới thiệu các chức năng phức tạp và sửa đổi nhiều chức năng gốc, là lưu trữ giá trị trong một tệp tạm thời và đọc / ghi nó khi cần thiết.

Cách tiếp cận này đã giúp tôi rất nhiều khi tôi phải giả lập một hàm bash được gọi nhiều lần trong một trường hợp kiểm tra dơi.

Ví dụ, bạn có thể có:

# Usage read_value path_to_tmp_file
function read_value {
  cat "${1}"
}

# Usage: set_value path_to_tmp_file the_value
function set_value {
  echo "${2}" > "${1}"
}
#----

# Original code:

function test1() {
  e=4
  set_value "${tmp_file}" "${e}"
  echo "hello"
}


# Create the temp file
# Note that tmp_file is available in test1 as well
tmp_file=$(mktemp)

# Your logic
e=2
# Store the value
set_value "${tmp_file}" "${e}"

# Run test1
test1

# Read the value modified by test1
e=$(read_value "${tmp_file}")
echo "$e"

Hạn chế là bạn có thể cần nhiều tệp tạm thời cho các biến khác nhau. Và bạn cũng có thể cần phát hànhsync lệnh để duy trì nội dung trên đĩa giữa một thao tác ghi và đọc.


-1

Bạn luôn có thể sử dụng bí danh:

alias next='printf "blah_%02d" $count;count=$((count+1))'
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.