Bash 스크립트용 dd 스타일 매개변수

Bash 스크립트용 dd 스타일 매개변수

dd 스타일 bash 스크립트에 매개변수를 전달하고 싶습니다. 기본적으로 나는 원한다

./script a=1 b=43

같은 효과가 있다

a=1 b=43 ./script

나는 다음과 같은 방법으로 이를 달성할 수 있다고 생각합니다.

for arg in "$@"; do
   eval "$arg";
done

eval안전한 (즉, "$arg"정적 일치(코드 실행 없음)) 변수 할당을 보장하는 좋은 방법은 무엇입니까?

아니면 더 좋은 방법이 있나요? (간단하게 유지하고 싶었습니다).

답변1

eval 없이(및 수동 이스케이프 없이) bash에서 이 작업을 수행할 수 있습니다.

for arg in "$@"; do
  if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; then
    declare +i +a +A "$arg"
  fi
done

편집하다:Stéphane Chazelas의 의견에 따라 할당된 변수가 배열 또는 정수 변수로 선언되는 것을 방지하기 위해 선언에 플래그를 추가했습니다. 이렇게 하면 많은 경우 인수의 값 부분을 declare평가 하지 않게 됩니다 key=val. ( +a예를 들어 설정할 변수가 배열 변수로 선언된 경우 오류가 발생합니다.) 이러한 모든 취약점은 이 구문을 사용하여 기존(배열 또는 정수) 변수를 재할당하는 것과 관련이 있습니다. 쉘 변수로 알려져 있습니다.

실제로 이는 동일한 eval솔루션에 영향을 미치는 주입 공격 클래스의 한 예일 뿐입니다. 알려진 매개변수 이름만 허용하는 것이 명령줄에 나타나는 변수를 맹목적으로 설정하는 것보다 훨씬 낫습니다. ( PATH예를 들어, 명령줄에서 설정했다면 어떤 일이 일어날지 생각해 보세요. 또는 PS1다음 프롬프트가 표시될 때 발생할 일부 평가를 포함하도록 재설정하세요.)

저는 bash 변수를 사용하는 것보다 명명된 매개변수의 연관 배열을 사용하는 것을 선호합니다. 이는 설정하기 쉽고 안전합니다. 또는 실제 bash 변수를 설정할 수 있지만 해당 이름이 유효한 인수의 연관 배열에 있는 경우에만 가능합니다.

후자 접근 방식의 예는 다음과 같습니다.

# Could use this array for default values, too.
declare -A options=([bs]= [if]= [of]=)
for arg in "$@"; do
  # Make sure that it is an assignment.
  # -v is not an option for many bash versions
  if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= &&
        ${options[${arg%%=*}]+ok} == ok ]]; then
    declare "$arg"
    # or, to put it into the options array
    # options[${arg%%=*}]=${arg#*=}
  fi
done

답변2

POSIX 1( / ... 와 같은 특수 변수 관련 문제를 피하기 $<prefix>var보다는 설정 ):$varIFSPATH

prefix=my_prefix_
for var do
  case $var in
    (*=*)
       case ${var%%=*} in
         "" | *[!abcdefghijiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]*) ;;
         (*) eval "$prefix${var%%=*}="'${var#*=}'
       esac
  esac
done

으로 호출되며 myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2다음을 할당합니다.

my_prefix_x <= 1
my_prefix_PATH <= /tmp/evil
my_prefix_1 <= 2

답변3

하드코딩된 접두사로 리팩터링된 lcd047의 솔루션 DD_OPT_:

while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
  eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
done

프로스트슈츠리팩토링의 대부분은 칭찬받을 가치가 있습니다.

소스 파일에 전역 변수로 넣었습니다.

DD_OPTS_PARSE=$(cat <<'EOF'
  while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
    eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
  done
EOF
)

eval "$DD_OPTS_PARSE"모든 마법을 발휘해보세요.

함수 버전은 다음과 같습니다.

DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"

사용 중:

eval "$DD_OPTS_PARSE_LOCAL"

내가 하나 만들었어환매 계약그 외에도 테스트와 README.md가 있습니다. 그런 다음 작성 중이던 Github API CLI 래퍼에서 이것을 사용했고, 위의 github 클론을 설정하는 데 동일한 래퍼를 사용했습니다.환매 계약(부팅하는 것은 재미 있습니다).

bash 스크립트에 인수를 안전하게 전달하는 데는 한 줄이면 충분합니다. 즐기다. :)

답변4

내 시도:

#! /usr/bin/env bash
name='^[a-zA-Z][a-zA-Z0-9_]*$'
count=0
for arg in "$@"; do
    case "$arg" in
        *=*)
            key=${arg%%=*}
            val=${arg#*=}

            [[ "$key" =~ $name ]] && { let count++; eval "$key"=\$val; } || break

            # show time
            if [[ "$key" =~ $name ]]; then
                eval "out=\${$key}"
                printf '|%s| <-- |%s|\n' "$key" "$out"
            fi
            ;;
        *)
            break
            ;;
    esac
done
shift $count

# show time again   
printf 'arg: |%s|\n' "$@"

RHS의 거의 모든 쓰레기를 처리할 수 있습니다.

$ ./assign.sh Foo_Bar33='1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0' '1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33'
|Foo_Bar33| <-- |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0|
arg: |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33|

$ ./assign.sh a=1 b=2 c d=4
|a| <-- |1|
|b| <-- |2|
arg: |c|
arg: |d=4|

관련 정보