함수 내에서 로컬로 $path 배열을 설정하는 덜 복잡한 방법이 있습니까?

함수 내에서 로컬로 $path 배열을 설정하는 덜 복잡한 방법이 있습니까?

$path다음 코드 조각에 표시된 것보다 배열의 로컬 버전을 설정하는 데 덜 힘든 방법이 있습니까 ?

foo () {
    local holdpath
    holdpath=($path)
    local path
    path=($holdpath)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}

구체적으로 카바레 쇼를 말하는 것인데 holdpath

내가 정의한다면

foo () {
    local path=($path)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}

...첫 번째 할당으로 인해 오류가 path발생했습니다 . bad pattern물론 내가 정의한다면

foo () {
    local path
    path=($path)
    if ( some_condition ) path=( $PREFIX $path )

    # do stuff
}

...첫 번째 할당은 path아무런 차이가 없습니다(즉, 결과를 변경하지 않고 생략할 수 있음). 할당이 있든 없든 $path비어 있습니다.

편집하다:

다음 스크립트는 지금까지 받은 다양한 제안을 테스트합니다.

foo_0 () {
  echo ${#path}
  local PATH=$PATH
  echo ${#path}
}

foo_1 () {
  echo ${#path}
  eval "local path; path=(${(q)path})"
  echo ${#path}
}

foo_2 () {
  echo ${#path}
  eval "$(local -p path)"
  echo ${#path}
}

for i ( 0 1 2 ) {
  fn=foo_$i
  echo "# $fn"
  $fn
  echo
}

출력은 다음과 같습니다

# foo_0
22
22

# foo_1
22
1

# foo_2
22
22

foo_0따라서 및 의 출력은 foo_2적어도 제가 달성하려는 것과 일치합니다. 위에 주어진 것처럼 작동하지 않는 것들이 있지만 할당하는 동안 foo_1제거했습니다 .(q)path

foo_1 () {
  echo ${#path}
  eval "local path; path=($path)"
  echo ${#path}
}

foo_0...그러면 출력은 및 의 출력과 일치합니다 foo_2. 불행하게도 한정자의 문서를 몇 번 읽어도 q원래 레시피에서 어떤 역할을 하는지 잘 이해가 되지 않습니다.

또한 다음 명령줄 변형이 foo_0위의 변형과 다른 이유를 이해할 수 없습니다.

% (foo_0a () { echo ${#path}; local PATH=$PATH; echo ${#path} }; foo_0a)
22
1

해당 명령줄 변형인 FWIW는 foo_1스크립트 foo_2의 원본과 동일한 결과를 생성합니다.

% (foo_1a () { echo ${#path}; eval "local path; path=(${(q)path})"; echo ${#path} }; foo_1a)
22
1
% (foo_2a () { echo ${#path}; eval "$(local -p path)"; echo ${#path}; }; foo_2a)
22
22

또한 위의 모든 경우에서 원인 보다는 echo ${#path}결과는 지역 변수에 공백으로 구분된 단일 문자열의 모든 개별 경로가 포함되어 있다는 것입니다.122$path

답변1

PATH배열 대신 스칼라 형식을 사용하십시오 path. 둘 중 하나를 만들면 둘 다 효과적으로 현지화됩니다. 따라서 다음과 같습니다.

foo() {
  local PATH=$PATH
  if ( some_condition ) path=( $PREFIX $path )

  # do stuff
}

(일부 경로 구성 요소가 포함된 경우에는 작동하지 않습니다 :.)

안타깝게도 로컬 배열 매개변수는 명령문에서 초기화할 수 없으므로 원래 값으로 초기화할 수 없습니다.

답변2

그리고묶음배열을 사용할 수 있습니다리치의 대답, 일반적으로 다음과 같이 할 수 있습니다.

foo() {
  eval "local array; array=(${(q)array[@]})"
  ...
}

이는 (q)배열 요소에 대한 참조입니다. 예를 들어 와 같은 값의 경우 로 $PATH확장 됩니다 . 문자열이 에 전달되므로 이러한 공백과 달러 문자를 이스케이프해야 합니다 ./foo bar:/x$y"${(q)path[@]}"/foo\ bar /x\$yeval

다음과 같이 할 수도 있습니다.

foo() {
  eval "$(local -p array)"
  ...
}

모든 유형의 변수에서 작동하지만 이로 인해 추가 프로세스가 생성됩니다.

관련 정보