bash 쉘 스크립트에서 모든 인수를 전파하십시오.


851

다른 스크립트를 호출하는 매우 간단한 스크립트를 작성 중이며 현재 스크립트에서 실행중인 스크립트로 매개 변수를 전파해야합니다.

예를 들어, 내 스크립트 이름은 foo.sh및 전화bar.sh

foo.sh :

bar $1 $2 $3 $4

각 매개 변수를 명시 적으로 지정하지 않고 어떻게해야합니까?



답변:


1404

실제로 매개 변수가 동일하게 전달되도록하려면 "$@"일반 대신 사용하십시오 $@.

관찰 :

$ cat foo.sh
#!/bin/bash
baz.sh $@

$ cat bar.sh
#!/bin/bash
baz.sh "$@"

$ cat baz.sh
#!/bin/bash
echo Received: $1
echo Received: $2
echo Received: $3
echo Received: $4

$ ./foo.sh first second
Received: first
Received: second
Received:
Received:

$ ./foo.sh "one quoted arg"
Received: one
Received: quoted
Received: arg
Received:

$ ./bar.sh first second
Received: first
Received: second
Received:
Received:

$ ./bar.sh "one quoted arg"
Received: one quoted arg
Received:
Received:
Received:

7
이것은 인용 / 이스케이프 된 문자열의 순수한 통과를 위해이 작업을 수행합니다. 관찰 : cat rsync_foo.sh #! / bin / bash echo "$ @"rsync "$ @"./rsync_foo.sh -n "bar me"bar2 bar me bar2skipping directory bar me 따옴표 나 이스케이프 된 문자열로 완성 된 실제 원래 명령 행을 볼 수있는 쉘 스크립트를 사용할 수 있습니까?
Mark Edington

3
플래그를 전달하는 것은 어떻습니까? 예를 들어, './bar.sh --with-물건'
나단 긴

4
Word Splitting의 주제를 더 잘 이해하고 싶은 분 은 여기를 참조하십시오.
Rany Albeg Wein

4
'arg with spaces'세 가지 예제에 대한를 포함하면 어떤 일이 발생하는지 보여줄 것을 제안합니다 . 나는 결과에 놀랐다. 잘하면 당신은 그들을 설명 할 수 있습니다.
Michael Scheper 2016 년

2
@MichaelScheper는, 어쨌든, ./foo.sh "arg with spaces"그리고 ./foo.sh 'arg with spaces'내가 주어진 예제에 추가의 제안이 어떤 도움이 될 것이라고 표시되지 않습니다, 그래서 100 % 동일하다.
Charles Duffy

475

들어 bash는 다른 본쉘 :

java com.myserver.Program "$@"

13
@ 아미르 : 아니, csh 아닙니다 . 모든 사람의 정신을 위해 : csh 스크립트를 작성하지 마십시오 . 그러나 $argv:q일부 csh 변형에서 작동 할 것이라고 생각 합니다.
Chris Johnsen

2
감사! 원하는대로 이것은 하나의 큰 인수가 아니라 스크립트가 수신 한 동일한 인수 세트를 전달합니다. 큰 따옴표가 필요합니다. 공백을 포함하는 인용 된 인수가있는 경우에도 작동합니다.
Andy Thomas

24
관련 : 쉘 스크립트가 Java를 실행하기위한 래퍼 역할을하는 경우 마지막 줄을 만드는 것을 고려하십시오. exec java com.myserver.Program "$@"이렇게하면 bash가 완료 될 때까지 기다리지 않고 java로 실행됩니다. 따라서 하나의 적은 프로세스 슬롯을 사용하고 있습니다. 또한 부모 프로세스 (스크립트를 실행 한)가 pid를 통해 그것을보고 'java'프로세스를 기대하는 경우, exec를 수행하지 않으면 비정상적인 일이 중단 될 수 있습니다. exec는 java가 동일한 pid를 상속하게합니다.
greggo

7
@dragonxlwang : 당신은, 만약 쉘 지원을 (예를 들어 배열 변수를 사용할 수 배쉬 , zsh을 할인율 : 다른 사람 있지만, 일반되지 Bourne- 또는 POSIX 쉘) 인수args=("$@")별도의 쉘 "단어"로 각 요소를 확장 ( 와 (과 "$@") 유사합니다 "${args[@]}".
Chris Johnsen

1
"$@"인수에서 공백을 이스케이프하거나 널 (null) 문자 또는 기타 특수 문자를 이스케이프하면 실패하는 것과 같이를 사용할 때 명심해야 할 "gotchas"가 있습니까?
IQAndreas

97

사용하십시오 "$@"(모든 POSIX 호환 가능).

[...] bash는 "$ @"변수를 특징으로하며, 공백으로 구분 된 모든 명령 행 매개 변수로 확장됩니다.

에서 배쉬 예에 의해 .


6
"$ @"는 $ @를 인용하는 것이 아니라 실제로 다른 내장 변수입니까?
ben

5
@ben 단일 변수이지만 (브로큰)과 다른 유용한 값을 가지려면 큰 따옴표가 필요합니다 $*. 나는 여기에 역사적 진보가 있다고 믿는다. $*설계된대로 작동하지 않았으므로 $@이를 대체하기 위해 발명되었습니다. 그러나 인용 규칙은 그것이 무엇인지, 그 주위의 큰 따옴표는 여전히 필요합니다 (또는 깨진 $*의미론으로 되돌아갑니다 ).
tripleee

7
"그래서"$ @ "는 $ @ 주위를 인용 할뿐만 아니라 다른 내장 변수도 유효합니까?" -모든 의도와 목적을 위해 예 : stackoverflow.com/a/28099707/162094
Stuart Berg

1
당신은 스크립트가 포함 된 호출하는 경우 echo "$@"로서 ./script.sh a "b c" d당신은 얻을 a b c d대신에 a "b c" d매우 큰 차이이다.
isarandi

7
@isarandi 출력에 더 이상 따옴표가 포함되어 있지 않다는 것이 사실이지만, 예상했던 것입니다 ...하지만 스크립트 내에서 echo세 개의 인수를받습니다 "a" "b c" "d". 그러나 당신이 사용했다면 당신 for i in "$@"; do echo $i; done은 얻을 a⏎b c⏎d것이다.
FeRD

64

나는 이것이 잘 대답되었다는 것을 알고 있지만 여기에 "$ @"$ @ "$ *"와 $ *의 비교가 있습니다.

테스트 스크립트의 내용 :

# cat ./test.sh
#!/usr/bin/env bash
echo "================================="

echo "Quoted DOLLAR-AT"
for ARG in "$@"; do
    echo $ARG
done

echo "================================="

echo "NOT Quoted DOLLAR-AT"
for ARG in $@; do
    echo $ARG
done

echo "================================="

echo "Quoted DOLLAR-STAR"
for ARG in "$*"; do
    echo $ARG
done

echo "================================="

echo "NOT Quoted DOLLAR-STAR"
for ARG in $*; do
    echo $ARG
done

echo "================================="

이제 다양한 인수로 테스트 스크립트를 실행하십시오.

# ./test.sh  "arg with space one" "arg2" arg3
=================================
Quoted DOLLAR-AT
arg with space one
arg2
arg3
=================================
NOT Quoted DOLLAR-AT
arg
with
space
one
arg2
arg3
=================================
Quoted DOLLAR-STAR
arg with space one arg2 arg3
=================================
NOT Quoted DOLLAR-STAR
arg
with
space
one
arg2
arg3
=================================

1
간결한 데모와이 답변에 대한 기여.
멀린

33
#!/usr/bin/env bash
while [ "$1" != "" ]; do
  echo "Received: ${1}" && shift;
done;

args가 스크립트에 어떻게 들어오는 지 테스트 할 때 이것이 더 유용 할 것이라고 생각했습니다.


6
이것은 확실히 그의 질문에 대답하는 데 도움이되지 않았지만 이것은 실제로 유용합니다. 공감!
Dario Russo

2
빈 매개 변수가 전달되면 중단됩니다. 다음을 확인해야합니다$#
Sebi

좋은 인수 테스터, 동의 "", ''어떤 인수가 없다면 또한 침묵, 인수로. 이 문제를 해결하려고했지만 for 루프와 카운터가 필요합니다 $#. 방금 끝에 이것을 추가했습니다.echo "End of args or received quoted null"
Merlin

8

내 SUN Unix에는 많은 제한이 있으며 "$ @"도 원하는대로 해석되지 않았습니다. 해결 방법은 $ {@}입니다. 예를 들어

#!/bin/ksh
find ./ -type f | xargs grep "${@}"

그건 그렇고, 유닉스가 grep -r을 지원하지 않기 때문에이 특정 스크립트를 가져야했습니다.


이것은 배쉬 질문이다. 당신은 사용ksh
트리플

6

$@다른 문자와 함께 따옴표로 묶은 문자열에 포함하면 여러 인수가있을 때 동작이 매우 이상하며 첫 번째 인수 만 따옴표 안에 포함됩니다.

예:

#!/bin/bash
set -x
bash -c "true foo $@"

수율 :

$ bash test.sh bar baz
+ bash -c 'true foo bar' baz

그러나 먼저 다른 변수에 할당하십시오.

#!/bin/bash
set -x
args="$@"
bash -c "true foo $args"

수율 :

$ bash test.sh bar baz
+ args='bar baz'
+ bash -c 'true foo bar baz'

3
나는 그것이 당황하다는 것을 부정하지는 않지만 실제로 "$@"bash 의 의미 내에서 의미가 있습니다. 또한와의 주요 차이점 $@$*두 가지가 모두 유용한 이유를 설명하는 데 도움이됩니다. 로부터 bash(1)man 페이지 특수 매개 변수 섹션 : " *- 확장 따옴표 내에서 발생하는 경우, 각 매개 변수, [...] 즉의 값을 하나의 단어로 확장 "$*"동등하는하는 "$1c$2c..."c이다 $IFS]." 실제로 첫 번째 예제 $*대신 $@대신를 사용하면 두 번째 버전과 동일한 출력을 얻을 수 있습니다.
FeRD

2
이제와 비교하십시오 "$@". 다시 사람이 페이지에서 : " @. - 확장 따옴표 내에서 발생하는 경우, 각 매개 변수는 별도의 단어로 확장 즉, "$@"동일합니다 "$1" "$2"이중 인용 확장이 단어 내에서 발생하는 경우, 첫 번째 매개 변수의 확장이 가입되어 ... "는 원래 단어의 시작 부분과 함께 마지막 매개 변수의 확장은 원래 단어의 마지막 부분과 결합됩니다." ... 그리고 실제로 코드가 있었다면 net bash -c "true foo $@ bar baz"처럼 코드 를 실행하십시오 . test.sh one twobash -c 'true foo one' 'two bar baz'
FeRD

1
워드 프로세서의 인용과에 대한 정보를 주셔서 감사합니다 $*, 나는 그것이 존재한다는 것을 잊지 것 같다 ..
ColinM

허. 나는 반대입니다. $@처음으로 쉘 스크립팅을 시작할 때 견인력을 얻고 있었지만 여전히 거기에 있다는 것을 상기시켜야합니다. "$*"스크립트에서 사용되는 것이 일반적이었습니다 . 그러면 저자는 모든 인수를 함께 스매싱한다는 것을 알고 있었기 때문에 단어 분리와 함께 복잡한 말도 안되는 모든 방식을 시도 "$*"하거나 루핑을 통해 arg 목록을 재구성합니다. 이상 shift만 사용 ... 하나 하나 아래를 당겨 $@을 해결해에게 그것을. (즉 bash는도 액세스 배열 구성원에 같은 연상 기호를 사용하는 데 도움을줍니다 : ${var[*]}그들 모두를위한 단어로, ${var[@]}단어의 목록.)
FeRD

여기서 진짜 문제는 당신이 bash -c전혀 이해가되지 않는 방식으로 사용 하고 있다는 것입니다.
11

4

때때로 당신은 (예를 들어, 모든 인수를 전달하기를 원하지만 플래그로 시작 --flag)

$ bar --flag "$1" --flag "$2" --flag "$3"

다음과 같은 방법으로이를 수행 할 수 있습니다.

$ bar $(printf -- ' --flag "%s"' "$@")

참고 : 당신이 인용합니다 추가 필드 분할을 방지 %s하고 $@, 단일 문자열을 피하기 위해, 당신의 서브 쉘을 인용 수 없습니다 printf.


3

공백이나 이스케이프 문자가있는 경우를 제외하고는 잘 작동합니다. 이 경우 인수를 캡처하여 스크립트 내부의 ssh로 보내는 방법을 찾지 못했습니다.

이것은 유용 할 수 있지만 너무 추합니다

_command_opts=$( echo "$@" | awk -F\- 'BEGIN { OFS=" -" } { for (i=2;i<=NF;i++) { gsub(/^[a-z] /,"&@",$i) ; gsub(/ $/,"",$i );gsub (/$/,"@",$i) }; print $0 }' | tr '@' \' )

3

여기에 많은 대답이 권장 $@되거나 $*인용되지 않고 인용되지만, 이것이 실제로하는 일과 왜 그렇게 해야하는지 설명하는 사람은 없습니다. 이 답변 에서이 훌륭한 요약을 훔치도록하겠습니다 .

여기에 이미지 설명을 입력하십시오

따옴표는 모든 차이를 만들며 따옴표가 없으면 동일한 동작을합니다.

내 목적을 위해 하나의 스크립트에서 다른 스크립트로 매개 변수를 전달해야했으며 최상의 옵션은 다음과 같습니다.

# file: parent.sh
# we have some params passed to parent.sh 
# which we will like to pass on to child.sh as-is

./child.sh $*

따옴표가 없으며 $@위의 상황에서도 잘 작동합니다.


2

bar "$@" 에 해당합니다 bar "$1" "$2" "$3" "$4"

따옴표가 중요합니다!

"$@", $@, "$*"또는 $*이에 설명 된대로 탈출 및 연결에 관한 것이다 각 행동하라 약간 다른 유래 대답 .

밀접하게 관련된 유스 케이스 하나는 다음 과 같이 인수 안에 주어진 모든 인수를 전달하는 것입니다.

bash -c "bar \"$1\" \"$2\" \"$3\" \"$4\"".

나는 이것을 달성하기 위해 @kvantour의 변형을 사용합니다.

bash -c "bar $(printf -- '"%s" ' "$@")"

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