인용 된 매개 변수를 수신하고 다시 전달하는 Bash 스크립트


98

중첩 스크립트에서 안전하게 수신 할 수 있도록 bash 스크립트의 인용 된 매개 변수를 얻으려고합니다. 어떤 아이디어?

test.sh

#!/bin/bash
echo $*
bash myecho.sh $*

myecho.sh

#!/bin/bash
 echo $1
 echo $2
 echo $3
 echo $4

견본:

bash test.sh aaa bbb '"ccc ddd"'

결과:

aaa bbb "ccc ddd"
aaa
bbb
"ccc
ddd"

원하는 결과

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd

2
방금 그 질문을하려고했습니다! 좋은 타이밍.
Scottie T

답변:


70
#!/bin/bash
echo $*
bash myecho.sh "$@"

"$ @"구조는 bash에 한정되지 않으며 모든 POSIX 쉘에서 작동해야합니다 (적어도 대시에서는 작동 함). 또한 원하는 출력이 주어지면 추가 수준의 인용이 필요하지 않습니다. IE는 위의 스크립트를 다음과 같이 호출합니다.

./test.sh 1 2 "3 4"

5
"$ @"는 Korn 및 Bash를 포함한 모든 Bourne 쉘 또는 Bourne 쉘 파생물 (1978 년 이후)에서 작동합니다. 아마도 95 %의 경우 "$ @"를 사용하는 것은 정확하고 $ *는 잘못되었습니다.
Jonathan Leffler

좋은! 하지만 변수에 "있는 그대로" 저장할 수 있는 방법이 있는지 아십니까 ? 원본 $@은 함수 내에서 사용할 수 없습니다 (함수 인수로 덮어 쓰기 때문에). 나는 노력 foovar="$@"foovar=$@+ "$foovar"기능과 아무도 일하지 : - /
bitifet

143

"$ @"(따옴표로 묶인 달러)를 사용하여 매개 변수를 아래 첨자로 전달하려고합니다. 이렇게 ....

ls-color.sh:

#!/bin/bash
/bin/ls --color=auto "$@"    # passes though all CLI-args to 'ls'


이유는 .....

로부터 배쉬 man 페이지 :

$*-1부터 시작하여 위치 매개 변수로 확장됩니다. 큰 따옴표 안에 확장이 발생하면 IFS 특수 변수의 첫 번째 문자로 구분 된 각 매개 변수의 값이있는 단일 단어로 확장됩니다. 즉, "$*"와 동일합니다 "$1c$2c...". 여기서 c는 IFS 변수 값의 첫 번째 문자입니다. IFS가 설정되지 않은 경우 매개 변수는 공백으로 구분됩니다. IFS가 널인 경우 매개 변수는 구분 기호없이 결합됩니다.

$@-1부터 시작하여 위치 매개 변수로 확장됩니다. 큰 따옴표 안에 확장이 발생하면 각 매개 변수가 별도의 단어로 확장됩니다. 즉, "$@"동등 "$1" "$2" ...이중 인용 확장 단어 내에서 발생하는 경우, 상기 제 파라미터의 확장은 일본어 단어의 시작 부분에 접합되고, 최종 파라미터의 확장은 기존의 마지막 부분에 접합되고 워드. 거기에는 위치 매개 변수가 없을 때 "$@"$@아무것도 확장 (즉, 그들은 제거된다).


데모 스크립트 설정 ...

echo 'echo -e "\$1=$1\n\$2=$2\n\$3=$3\n\$4=$4"' > echo-params.sh
echo './echo-params.sh $*' > dollar-star.sh
echo './echo-params.sh $@' > dollar-at.sh
echo './echo-params.sh "$*"' > quoted-dollar-star.sh
echo './echo-params.sh "$@"' > quoted-dollar-at.sh
chmod +x *.sh

"$@"-quoted-dollar-at는 args를 서브 쉘로 다시 전달하기위한 신원 변환 입니다 (약 99 %의 시간, 이것이 당신이 의도 한 것입니다) :

./quoted-dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2=            
  # $3= 'cc cc'
  # $4= "ddd ddd"

"$*"-quoted -dollar-star 는 args를 단일 문자열로 분쇄합니다 (실제로이 동작을 원하는 시간의 ~ 1 %, 예 : 조건부 :) if [[ -z "$*" ]]; then ...:

./quoted-dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa  'cc cc' "ddd ddd"   
  # $2=                     
  # $3=             
  # $4=

$*/ $@-따옴표없이 두 형식 모두 한 수준의 따옴표를 제거하고 기본 문자열에서 공백을 해석하지만 따옴표 문자는 무시합니다 (거의 항상 이것은 실수입니다).

./dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc                  
  # $3= cc'
  # $4= "ddd

./dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc
  # $3= cc'
  # $4= "ddd

재미를 원한다면 "$ @"를 사용하여 원하는만큼 깊이 중첩하고, 원하는 경우 args 스택에서 요소를 밀어 내고 터뜨릴 수 있습니다.

function identity() {
  "$@"
}
set -x
identity identity identity identity identity echo Hello \"World\"
# + identity identity identity identity identity echo Hello '"World"'
# + identity identity identity identity echo Hello '"World"'
# + identity identity identity echo Hello '"World"'
# + identity identity echo Hello '"World"'
# + identity echo Hello '"World"'
# + echo Hello '"World"'
# Hello "World"

1
설명 해주셔서 감사합니다. grep 별칭에 "$ *"를 사용했습니다.
darkless

당신은 내 하루를 구합니다!
xyz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.