programing

bash의 함수 내에서 글로벌 변수를 수정하는 방법은 무엇입니까?

stoneblock 2023. 5. 19. 23:57

bash의 함수 내에서 글로벌 변수를 수정하는 방법은 무엇입니까?

저는 이것으로 일하고 있습니다.

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

아래와 같은 스크립트가 있습니다.

#!/bin/bash

e=2

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

test1 
echo "$e"

반환되는 항목:

hello
4

하지만 함수의 결과를 변수에 할당하면 전역 변수는e수정되지 않음:

#!/bin/bash

e=2

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

ret=$(test1)

echo "$ret"
echo "$e"

반환:

hello
2

저는 이 경우에 eval을 사용하는 것에 대해 들어본 적이 있어서,test1:

eval 'e=4'

하지만 같은 결과입니다.

왜 수정되지 않았는지 설명해 주시겠습니까?어떻게 하면 그 메아리를 살릴 수 있을까요?test1에서 합니다.ret글로벌 변수도 수정할 수 있습니까?

명대를즉경는우사하용)를 사용할 때,$(...)구성), 하위 셸을 만드는 중입니다.하위 셸은 상위 셸에서 변수를 상속하지만, 하위 셸은 상위 셸의 환경을 수정할 수 없습니다.

의 변수 ㅠㅠe하위 셸 내에서 설정되지만 상위 셸 내에서는 설정되지 않습니다.하위 셸에서 상위 셸로 값을 전달하는 두 가지 방법이 있습니다.먼저 stdout으로 출력한 다음 명령 대체를 사용하여 캡처할 수 있습니다.

myfunc() {
    echo "Hello"
}

var="$(myfunc)"

echo "$var"

위의 출력:

Hello

~에는 0 ~ 255 범의숫값자대에해다사수있다를 할 수 .return번호를 종료 상태로 전달:

mysecondfunc() {
    echo "Hello"
    return 4
}

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

echo "$var - num is $num_var"

다음 출력은 다음과 같습니다.

Hello - num is 4

경우필 4.1이요를 사용하는 4합니다.{fd}또는local -n.

나머지는 bash 3.x에서 작동할 것입니다.때문에 완전히 확신할 수 없습니다.printf %q이것은 bash 4 기능일 수 있습니다.

요약

다음과 같이 예제를 수정하여 원하는 효과를 보관할 수 있습니다.

# 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"

원하는 대로 인쇄:

hello
4

이 솔루션은 다음과 같습니다.

  • 작업대상에서 합니다.e=1000 무너.
  • $?$?

유일한 부작용은 다음과 같습니다.

  • 그것은 현대적인 것이 필요합니다.bash.
  • 포크가 더 자주 걸려요.
  • )._)
  • 파일 설명자 3을 희생합니다.
    • 필요하면 다른 FD로 변경할 수 있습니다.
      • _capture의 모든 발생을 대체합니다.3다른 번호로

다음은 이 레시피를 다른 스크립트에도 적용하는 방법을 설명하는 것입니다.

그 문제는

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

산출물

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

원하는 산출물이 있는 동안.

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

문제의 원인

셸 변수(또는 일반적으로 환경)는 부모 프로세스에서 자식 프로세스로 전달되지만 그 반대는 아닙니다.

출력 캡처를 수행하는 경우 일반적으로 하위 셸에서 실행되므로 변수를 되돌리기가 어렵습니다.

어떤 사람들은 심지어 그것을 고치는 것이 불가능하다고 말합니다.이것은 잘못된 것이지만, 문제를 해결하는 것은 오래 전부터 알려진 어려운 일입니다.

이 문제를 가장 잘 해결하는 방법에는 여러 가지가 있습니다. 이는 사용자의 필요에 따라 다릅니다.

다음은 방법에 대한 단계별 가이드입니다.

변수를 부모 셸로 되돌리기

변수를 부모 셸로 되돌리는 방법이 있습니다.입니다. 은 하만이위길다입이니, 왜면하것은냐를 사용하기 입니다.eval만약 부적절하게 행동한다면, 여러분은 많은 나쁜 일들을 감수할 것입니다.하지만 제대로만 된다면, 버그가 없다면, 이것은 완벽하게 안전합니다.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

인쇄물

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

이것은 위험한 것에도 효과가 있습니다.

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

인쇄물

; /bin/echo *

이는 다음 때문입니다.printf '%q'셸 컨텍스트에서 안전하게 재사용할 수 있도록 모든 것을 인용합니다.

하지만 이것은 고통입니다.

이것은 보기 흉할 뿐만 아니라, 입력하기에도 크기 때문에 오류가 발생하기 쉽습니다.단 한 번의 실수로 당신은 망한 거죠, 그렇죠?

음, 우리는 쉘 레벨에 있으니 당신은 그것을 개선할 수 있습니다.보고 싶은 인터페이스만 생각하면 구현할 수 있습니다.

셸이 처리하는 방식인 증강

한 걸음 뒤로 돌아가서 우리가 무엇을 하고 싶은지 쉽게 표현할 수 있는 API에 대해 생각해 보겠습니다.

음, 우리가 원하는 것은 무엇입니까?d()기능?

출력을 변수로 캡처하려고 합니다.좋아요. 그렇다면 이에 대한 API를 구현해 보겠습니다.

# 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="$("$@")"
}

자, 글을 쓰는 대신에

d1=$(d)

우리는 쓸 수 있습니다.

capture d1 d

음, 이것은 우리가 크게 변하지 않은 것처럼 보입니다, 다시 말하지만, 변수들은 뒤로 넘어가지 않습니다.d좀 더 입력해야 합니다.

하지만 이제 우리는 기능에 잘 싸여 있기 때문에 껍질의 모든 힘을 그것에 던질 수 있습니다.

재사용하기 쉬운 인터페이스에 대해 생각해 보십시오.

두 번째는 우리가 드라이(반복하지 말 것)하기를 원한다는 것입니다.그래서 우리는 절대로 이런 것을 입력하고 싶지 않습니다.

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여기에는 중복이 있을 뿐만 아니라 항상 올바른 맥락에서 반복되는 오류가 있습니다.스크립트에서 1000번 사용한 후 변수를 추가하면 어떻게 됩니까?당신은 "" "" "" "" "" "" "" "" "" ""로 전화를 거는 .d관련되어 있습니다.

그러니 놔둬요x멀리, 그래서 우리는 쓸 수 있습니다:

_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

산출물

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

은 이미 ( 이은이매좋보다하니입아우미다있니습것여히지만전하▁the▁(▁still▁this▁is다▁(보.local -n는 일반적인 경우에는 통하지 않습니다.bash3.x)

하지 마십시오.d()

마지막 솔루션에는 몇 가지 큰 결함이 있습니다.

  • d()합니다.
  • 의 내부 세부 정보를 사용해야 합니다.xcapture출력을 전달합니다.
    • 이 변수는 다음과 같은 이름을 가진 하나의 변수를 표시(태웁니다)합니다.output그래서 우리는 이것을 절대 되돌릴 수 없습니다.
  • 그것은 협력할 필요가 있습니다._passback

이것도 없앨 수 있나요?

물론, 할 수 있습니다!우리는 껍데기 속에 있기 때문에 이 일을 완수하기 위해 필요한 모든 것이 있습니다.

당신이 조금 더 가까이에 있는 통화를 보면.eval보시다시피, 우리는 이 위치에서 100% 통제권을 가지고 있습니다."내부"eval우리는 하위 껍질에 있기 때문에 부모 껍질에 나쁜 짓을 할 염려 없이 우리가 원하는 모든 것을 할 수 있습니다.

네, 좋습니다. 이제 바로 안쪽에 다른 포장지를 추가해 보겠습니다.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

인쇄물

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

그러나 이는 다시 한 번 큰 단점이 있습니다.

  • !DO NOT USE!마커는 여기에 있습니다. 왜냐하면 여기에는 쉽게 볼 수 없는 매우 나쁜 레이스 조건이 있기 때문입니다.
    • >(printf ..)백그라운드 작업입니다.그래서 그것은 여전히 실행될 수 있습니다._passback x실행 중입니다.
    • 다음을 추가하면 직접 확인할 수 있습니다.sleep 1; 앞에printf또는_passback._xcapture a d; echo 다음 그출음 다 력 출을 출력합니다.x또는a각각 첫째로
  • _passback x의 일부가 되어서는 안 됩니다._xcapture왜냐하면 이것은 그 레시피를 재사용하는 것을 어렵게 만들기 때문입니다.
  • 여기.$(cat)), 이 은 ), 이와 !DO NOT USE!저는 가장 짧은 길을 택했습니다.

하지만, 이것은 우리가 그것을 수정하지 않고 할 수 있다는 것을 보여줍니다.d() 없음)local -n)!

꼭 필요한 것은 아닙니다._xcapture전혀, 우리가 모든 것을 바로 쓸 수 있었기 때문에.eval.

그러나 일반적으로 이 작업을 수행하는 것은 그다지 읽을 수 없습니다.그리고 만약 여러분이 몇 년 후에 여러분의 대본으로 돌아온다면, 여러분은 아마도 큰 어려움 없이 그것을 다시 읽을 수 있기를 원할 것입니다.

경주를 시작합니다.

이제 레이스 상태를 수정해 보겠습니다.

비결은 다음 시간까지 기다리는 것일 수 있습니다.printf STDOUT를 출력합니다.x.

이를 보관하는 방법은 여러 가지가 있습니다.

  • 파이프는 다른 프로세스에서 실행되므로 셸 파이프를 사용할 수 없습니다.
  • 임시 파일을 사용할 수 있습니다.
  • 아니면 잠금 파일이나 피포 같은 것.이를 통해 잠금 또는 FIFO를 기다릴 수 있습니다.
  • 또는 다른 채널에서 정보를 출력한 다음 올바른 순서로 출력을 조립합니다.

마지막 경로를 따르는 것은 다음과 같이 보일 수 있습니다. (참고로 이 경로는 다음과 같습니다.)printf여기서 더 잘 작동하기 때문에 마지막):

_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

산출물

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

왜 이것이 맞습니까?

  • _passback xSTDOUT와 직접 대화합니다.
  • 과 FD3다른 할 수 있음에 " "'3>&1'과 함께 합니다.>&3.
  • $("${@:2}" 3<&-; _passback x >&3)▁the 뒤에 ._passbackSubshell 이 STDOUT 닫 때을 를때.
  • 그래서 그printf이전에는 발생할 수 없습니다._passback 동안이라도_passbacktakes.
  • 로 고는 다음과 .printf전에는 되지 않기 에, ▁from▁is▁command▁ar▁see▁is▁cannot다line없▁before,▁not▁the니▁so습완의 아티팩트를 볼 수 없습니다.printf 독립적으로printf구현됩니다.

첫 번째 그므로먼저러먼._passback실행한 행하고, 그다에를 실행합니다.printf.

이렇게 하면 하나의 고정 파일 설명자 3이 손실되어 레이스가 해결됩니다.물론 셸 스크립트에서 FD3가 비어 있지 않은 경우 다른 파일 설명자를 선택할 수 있습니다.

또한 참고하시기 바랍니다.3<&-FD3가 기능에 전달되도록 보호합니다.

더 일반적으로 만들기

_capture에속는부포니다함에 속하는 이 포함되어 있습니다.d()재사용 가능성의 관점에서 볼 때 좋지 않은 것입니다.어떻게 해결합니까?

것을 기능인 으로써, 은 음, 한, 추, 을 따서 ._첨부된.

이 기능은 실제 기능의 이름을 따서 불리고, 사물을 증가시킬 수 있습니다.이런 식으로, 이것은 어떤 주석으로 읽을 수 있기 때문에, 매우 읽기 쉽습니다.

_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

스틸 프린트

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

반송 코드에 대한 액세스 허용

누락된 비트가 하나뿐입니다.

v=$(fn)$?fn 이것을 입니다.그래서 당신도 아마 이것을 원할 것입니다.하지만 좀 더 큰 조정이 필요합니다.

# 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

인쇄물

23 42 69 FAIL

아직 개선의 여지가 많습니다.

  • _passback()으로 수할있다니습으로 제거할 수 .passback() { set -- "$@" "$?"; while [ 1 -lt $# ]; do printf '%q=%q;' "$1" "${!1}"; shift; done; return $1; }

  • _capture()로 제거할 수 있습니다.capture() { eval "$({ out="$("${@:2}" 3<&-; "$2_" >&3)"; ret=$?; printf "%q=%q;" "$1" "$out"; } 3>&1; echo "(exit $ret)")"; }

  • 솔루션은 파일 설명자(여기서는 3)를 내부적으로 사용하여 오염시킵니다.만약 당신이 FD에 합격한다면, 당신은 그것을 명심할 필요가 있습니다.
    :bash 버전에는 4.1 상은이 있습니다.{fd}사용하지 않는 FD를 사용합니다.
    (아마도 제가 방문할 때 여기에 솔루션을 추가할 것입니다.)
    이것이 제가 그것을 다음과 같은 별도의 기능에 넣는 이유입니다._capture 이 을 한 줄로 것은하지만, 점점 더와 이해를 때문입니다.

  • 호출된 함수의 STDERR도 캡처할 수 있습니다.또는 둘 이상의 파일 설명자를 변수와 주고받으려는 경우도 있습니다.
    저는 아직 해결책이 없지만, 여기에 하나 이상의 FD를 잡을 수 있는 방법이 있기 때문에 변수를 이런 식으로 되돌릴 수도 있습니다.

또한 다음 사항도 잊지 마십시오.

외부 명령이 아닌 셸 함수를 호출해야 합니다.

명령어에서 전달할 수 . (With 명령서환경변쉽수없방다습니법은있는전달할외부게에수를▁(with▁there▁out▁(mentwith▁variables다▁to없▁commands니▁is▁environLD_PRELOAD=하지만, 그것은 가능해야 합니다.하지만 이것은 완전히 다른 것입니다.

마지막 말

이것만이 가능한 해결책은 아닙니다.그것은 해결책의 한 예입니다.

언제나 그렇듯이 당신은 껍질 속에서 사물을 표현하는 많은 방법을 가지고 있습니다.그러니 자유롭게 개선하고 더 나은 것을 찾으세요.

여기에 제시된 솔루션은 완벽하지 않습니다.

  • 거의 테스트가 되지 않았으니 오타는 용서해주세요.
  • 개선의 여지가 많습니다. 위를 참조하십시오.
  • 현대적인 기능을 많이 사용합니다.bash그래서 아마도 다른 조개껍데기로 옮기기가 어려울 것입니다.
  • 그리고 제가 미처 생각하지 못한 몇 가지 기묘한 점들이 있을지도 모릅니다.

하지만 사용하기는 꽤 쉽다고 생각합니다.

  • "라이브러리"를 4줄만 추가합니다.
  • 셸 기능에 대해 "주석"을 한 줄만 추가합니다.
  • 일시적으로 하나의 파일 설명자만 사용할 수 있습니다.
  • 그리고 각 단계는 몇 년 후에도 이해하기 쉬워야 합니다.

당신이 하고 있는 일, 당신은 test1을 실행하고 있습니다.

$(test1)

하위 셸(하위 셸) 및 하위 셸은 상위 셸의 어떤 것도 수정할 수 없습니다.

bash 매뉴얼에서 찾을 수 있습니다.

확인하십시오.여기에 하위 셸이 생성됩니다.

아마도 당신은 파일을 사용할 수 있고, 파일 내부 함수에 글을 쓰고, 그 뒤에 파일에서 읽을 수도 있습니다.나는 변했다.e일로렬다시 을 구분 합니다.이 예에서는 배열을 다시 읽을 때 공백이 구분 기호로 사용됩니다.

#!/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]}"

출력:

hi
first second third
first
second
third

제가 만든 임시 파일을 자동으로 제거하려고 할 때도 비슷한 문제가 있었습니다.제가 생각해낸 해결책은 명령 대체를 사용하는 것이 아니라, 최종 결과를 취해야 하는 변수의 이름을 함수에 전달하는 것이었습니다.예.

#!/usr/bin/env bash

# array that keeps track of tmp-files
remove_later=()

# function that manages tmp-files
new_tmp_file() {
  file=$(mktemp)
  remove_later+=( "$file" )
  # assign value (safe form of `eval "$1=$file"`)
  printf -v "$1" -- "$file"
}

# function to remove all tmp-files
remove_tmp_files() { rm -- "${remove_later[@]}"; }

# define trap to remove all tmp-files upon EXIT
trap remove_tmp_files EXIT

# generate tmp-files
new_tmp_file tmpfile1
new_tmp_file tmpfile2

이를 OP에 적용하면 다음과 같습니다.

#!/usr/bin/env bash
    
e=2
    
function test1() {
  e=4
  printf -v "$1" -- "hello"
}
    
test1 ret
    
echo "$ret"
echo "$e"

작동하며 "반환 값"에 대한 제한이 없습니다.

라고 가정하면,local -n를 사용할 수 . 하면 할사수있경우, 다스크는기허다용니합능 을 사용할 수 있습니다.test1전역 변수 수정:

#!/bin/bash

e=2

function test1() {
  local -n var=$1
  var=4
  echo "hello"
}

test1 e
echo "$e"

다음과 같은 출력을 제공합니다.

hello
4

이것이 당신의 단말기에서 작동하는지는 잘 모르겠지만, 당신이 어떤 출력도 제공하지 않으면 자연스럽게 void 함수로 취급되어 글로벌 변수를 변경할 수 있다는 것을 알게 되었습니다.제가 사용한 코드는 다음과 같습니다.

let ran1=$(( (1<<63)-1)/3 ))
let ran2=$(( (1<<63)-1)/5 ))
let c=0
function randomize {
    c=$(( ran1+ran2 ))
    ran2=$ran1
    ran1=$c
    c=$(( c > 0 ))
}

필요한 변수를 효과적으로 수정하는 게임용 간단한 랜덤라이저입니다.

명령 대체는 하위 셸에서 수행되므로 하위 셸이 변수를 상속하는 동안 하위 셸이 종료되면 변수에 대한 변경 내용이 손실되기 때문입니다.

참조:

명령 대체, 괄호로 그룹화된 명령 및 비동기 명령은 셸 환경의 복제인 하위 셸 환경에서 호출됩니다.

복잡한 기능을 도입하고 원본 기능을 크게 수정하지 않고도 이 문제를 해결할 수 있는 방법은 값을 임시 파일에 저장하고 필요할 때 읽거나 쓰는 것입니다.

박쥐 테스트 케이스에서 여러 번이라는 배시 함수를 조롱해야 할 때 이 접근 방식이 큰 도움이 되었습니다.

예를 들어 다음과 같은 작업을 수행할 수 있습니다.

# 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"

단점은 여러 변수에 대해 여러 임시 파일이 필요할 수 있다는 것입니다.그리고 또한 당신은 발행해야 할 수도 있습니다.sync하나의 쓰기 작업과 읽기 작업 사이에 디스크의 내용을 유지하는 명령입니다.

항상 별칭을 사용할 수 있습니다.

alias next='printf "blah_%02d" $count;count=$((count+1))'

언급URL : https://stackoverflow.com/questions/23564995/how-to-modify-a-global-variable-within-a-function-in-bash