Bash: 서브셸에서 전역 변수 작성

Bash: 서브셸에서 전역 변수 작성

getopts여러 번 사용할 수 있도록 일부 논리를 함수로 이동하여 사용자에게 지정된 매개변수의 순서에 더 많은 유연성을 제공하려고 합니다 .

print-usage() {
echo "myssh [options] <host> [options] [-- ssh-options...]" >&2
exit 1
}

extra_args=()

parse-args() {
  while getopts ":hvV:" opt; do
    case ${opt} in
      (h)  print-usage ;;
      (v)  extra_args+=('-L 5900:localhost:5900')    ;;
      (V)  extra_args+=("-L $OPTARG:localhost:5900") ;;
      (\?) echo "Invalid option: -$OPTARG" >&2       ;;
      (:)  echo "Invalid option: -$OPTARG requires an argument" >&2 ;;
    esac
  done
  echo $((OPTIND -1))
}

shift $(parse-args $@)

host=$1
shift

shift $(parse-args $@)

ssh $host $extra_args $@

내 문제는 이것이 parse-args() { ... extra_args+=(...) }전역 변수에 영향을 미치지 않는다는 것입니다 extra_args. 나는 하위 쉘이 상위 범위 변수에 쓸 수 없으며 일반적으로 stdout을 사용해야 한다는 것을 알고 있지만 stdout을 이동된 정수로 사용했습니다.

이 문제는 일반적으로 어떻게 해결됩니까?

답변1

(태그된 대로) 사용하고 있으므로 bash배열 변수를 사용할 수 있습니다. 당신이 할 수 없는 일은 서브쉘 shift $(parse_args "$@")에 있는 this 와 같은 호출을 통해 전역 변수에 영향을 미치는 것입니다 . parse_args다음은 함수 외부에 값 배열을 전달하는 대체 솔루션입니다.

#!/bin/bash
#
extra_args1=()
extra_args2=()

usage() {
    echo "myssh [options] <host> [options] [-- ssh-options...]" >&2
    exit 1
}
    
parse_args() {
    local OPT OPTIND=1 OPTARG args=()
    while getopts ":hvV:" OPT
    do
        case "$OPT" in
            (h)   usage ;;
            (v)   args+=('-L' '5900:localhost:5900') ;;
            (V)   args+=('-L' "$OPTARG:localhost:5900") ;;
            (\?)  echo "Invalid option: -$OPTARG" >&2 ;;
            (:)   echo "Invalid option: -$OPTARG requires an argument" >&2 ;;
        esac
    done
    echo $((OPTIND -1)) "${args[@]}"
}

# Get number to shift plus set of arguments
extra_args1=($(parse_args "$@"))
shift ${extra_args1[0]}
unset extra_args1[0]

# Position dependent value
host="$1"
shift

# Get number to shift plus set of arguments
extra_args2=($(parse_args "$@"))
unset extra_args2[0]

# "${x[@]}" values are interpolated as quoted and vanish if fully empty
ssh "$host" "${extra_args1[@]}" "${extra_args2[@]}" "$@"

큰따옴표를 사용하면 "$@"개별 값 자체가 큰따옴표로 처리될 뿐만 아니라 확장할 값이 없으면 전체 확장이 사라지는 마법을 사용할 수 있습니다. 동일한 기능을 사용하여 "${extra_args1[@]}"확장을 처리할 수 있습니다."${extra_args2[@]}"

이 방법의 한 가지 잠재적인 단점은 그 a=($(function))자체가 와일드카드의 적용을 받기 때문에 function와일드카드가 반환되면 배열 할당의 일부로 확장된다는 것입니다 a. 이 문제에 대한 좋은 해결책이 없습니다.

답변2

파이프를 사용하여 가능한 솔루션입니다 FIFO. 함수에서 정의하는 대신 extra_args함수를 사용하여 파이프에 쓰고 extra_args함수를 호출한 후 읽습니다.

#!/bin/bash

trap "rm -rf extraargpipe" ERR EXIT
mkfifo extraargpipe
parseargs() {
 echo 1 > extraargpipe &
 echo 2 > extraargpipe &
}
parseargs
extra_args=$(cat extraargpipe)

echo ${extra_args}

FIFO 논리(또는 올바르게 기억한다면 실제로 경쟁 조건)로 인해 반환되지만 2 1잘못된 순서는 ssh정의한 옵션에 문제가 되지 않습니다. 비슷한 것을 만들고 싶다면 -o opt1,opt2,opt3그게 전부입니다.

임시 파일을 사용하여 거의 동일한 작업을 수행할 수 있습니다.

관련 정보