"$@"
쉘 스크립트에서는 필요에 따라 스크립트 매개변수를 인용하여 확장하는 것으로 이해됩니다 . 예를 들어 다음은 스크립트 매개변수를 gcc로 전달합니다.
gcc -fPIC "$@"
<<<
그러나 bash pass-to-stdin 구문을 사용하면 "@$"
예상대로 작동하지 않습니다.
#!/bin/bash
cat <<< "$@"
./test.sh foo "bar baz"
주어진 대로 스크립트를 호출하세요.
foo bar baz
나는 희망
foo "bar baz"
마치 쉘 프롬프트에서 작성된 것처럼 인수를 인쇄하는 쉘 스크립트를 작성하는 방법이 있습니까? 예: 힌트의 스크립트 매개변수를 포함하여 다음에 사용할 명령에 대한 힌트입니다.
답변1
"$@"
위치 인수당 하나의 인수로 구성된 위치 인수 목록으로 확장하세요 .
이 작업을 수행할 때:
set '' 'foo bar' $'blah\nblah'
cmd "$@"
cmd
호출은 빈 문자열 foo bar
및 3개의 매개변수를 사용하여 수행됩니다 blah<newline>blah
. 쉘은 execve()
다음과 같이 시스템 호출을 호출합니다.
execve("/path/to/cmd", ["cmd", "", "foo bar", "blah\nblah"], [envvars...]);
동일한 호출을 재현하기 위해 셸 명령줄(즉, 셸 언어의 코드)을 재구성하려면 다음을 수행할 수 있습니다.
awk -v q="'" '
function shellquote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
for (i = 1; i < ARGC; i++) {
printf "%s", sep shellquote(ARGV[i])
sep = " "
}
printf "\n"
}' cmd "$@"
또는 을 사용하여 zsh
다양한 유형의 견적을 요청하세요.
$ set '' 'foo bar' $'blah\nblah'
$ print -r -- cmd "${(q)@}"
cmd '' foo\ bar blah$'\n'blah
$ print -r -- cmd "${(qq)@}"
cmd '' 'foo bar' 'blah
blah'
$ print -r -- cmd "${(qqq)@}"
cmd "" "foo bar" "blah
blah"
$ print -r -- cmd "${(qqqq)@}"
cmd $'' $'foo bar' $'blah\nblah'
또는 zsh
, bash
또는 ksh93
(여기서는 bash
다른 쉘과 함께 YMMV)을 사용하십시오.
$ set '' 'foo bar' $'blah\nblah'
$ printf cmd; printf ' %q' "$@"; printf '\n'
cmd '' foo\ bar $'blah\nblah'
또한 쉘의 xtrace 옵션을 사용하여 쉘이 실행하려는 내용을 인쇄하도록 할 수도 있습니다:
$ (PS4=; set -x; : cmd "$@")
: cmd '' 'foo bar' 'blah
blah'
:
위에서는 위치 인수를 인수로 사용하여 no-op 명령을 실행했습니다 . cmd
내 쉘은 쉘에 다시 입력하기에 적합한 멋진 인용 방식으로 이를 인쇄합니다. 모든 쉘이 이 작업을 수행하는 것은 아닙니다.
답변2
`"$@"` expands to the script arguments, quoting them as needed
아니요, 그렇지 않습니다. 프로그램을 호출하려면목록매개변수, 각 매개변수는 문자열입니다. 쉘 프로그램을 실행하면 , 및 3개의 매개변수를 사용 하여 ./test.sh foo "bar baz"
호출이 구성됩니다 . (0번째 인수는 프로그램 이름입니다. 이를 통해 프로그램은 호출되는 이름을 알 수 있습니다.) 인용은 프로그램 호출의 기능이 아니라 쉘의 기능입니다. 쉘은 호출할 때 이 목록을 작성합니다../test.sh
foo
bar baz
"$@"
스크립트나 함수에 전달된 인수 목록을 이를 사용하는 호출의 인수 목록에 직접 복사합니다. 이러한 목록은 쉘 구문 분석되지 않으므로 인용이 포함되지 않습니다.
In에서는 cat <<< "$@"
단일 문자열이 예상되는 컨텍스트에서 사용합니다. "$@"
연산자는 <<<
문자열 목록이 아닌 문자열을 기대합니다. 이 경우 bash는 목록의 요소를 가져와서 공백으로 연결합니다.
set -x
스크립트 디버깅의 경우 ( 닫기 위해) 실행하면 set +x
실행 전에 각 명령이 인쇄되는 추적 모드가 활성화됩니다. Bash에서는 추적이 인용되고 명령을 셸에 다시 붙여넣을 수 있습니다(모든 sh
구현에서 이 작업을 수행하는 것은 아닙니다).
문자열이 있고 이를 셸 소스 구문으로 변환하고 다시 원래 문자열로 구문 분석하려는 경우 이를 작은따옴표로 묶고 문자열의 각 작은따옴표를 로 바꿀 수 있습니다 '\''
.
for x do
printf %s "'${x//\'/\'\\\'\'}' "
done
echo
문자열 대체 구문은 ksh93/bash/zsh/mksh에만 해당됩니다. 일반 sh에서는 문자열을 반복해야 합니다.
for raw do
quoted=
while case "$raw" in *\'*) true;; *) false;; esac; do
quoted="$quoted'\\''${raw%%\'*}"
raw="${raw#*\'}"
done
printf %s "'$quoted$raw' "
done
echo
답변3
"$@"
필요에 따라 인용하여 스크립트 매개변수로 확장합니다.
글쎄요. 실용적인 목적을 위해 충분히 가까워야 하며,참고 도서실제로 그렇게 말했다"$@" is equivalent to "$1" "$2" ...
따라서 두 개의 인수를 사용하면 다음 foo
과 bar baz
유사합니다.
echo "$@"
echo "$1" "$2"
echo "foo" "bar baz"
(인수에 일반 문자열뿐만 아니라 특수 문자가 포함된 경우를 제외하고는 확장 후 다시 확장되지 않습니다 $@
... $1
)
그러나 따옴표로 매개변수 대체를 고려하더라도 따옴표를 얻지 못하는 것처럼 $@
따옴표가 나타나지 않습니다 .echo
gcc
<<<
"$@"
== 규칙의 예외 "$1" "$2" ...
이며 명시적입니다.언급하다The result is supplied as a single string to the command on its standard input
매개변수 및 변수 확장, 따옴표 제거 등을 거친 후 따라서 평소와 같이 입력으로 <<< "foo"
만 제공되고 foo
동일한 방식으로 인수로만 somecmd "foo"
제공됩니다 foo
.
./test.sh foo "bar baz"
나는 스크립트가 호출 될 것으로 기대하고 있습니다 [...]foo "bar baz"
제안이 유지되는 경우에도 여전히 이어야 합니다 "foo" "bar baz"
. 쉘이나 실행 중인 명령은 실행 시 명령이 참조되는 내용을 알지 못합니다. 또는 언급할 따옴표가 있더라도 시스템 호출은 null로 끝나는 문자열 목록을 수신하며 따옴표는 셸 언어의 기능일 뿐입니다. 다른 언어에는 다른 규칙이 있을 수 있습니다.
답변4
bash의 대체 솔루션
q='"'; t=( "${@/#/$q}" ); u=( "${t[@]/%/$q}" ); echo ${u[@]}
Bash는 중첩 대체를 지원하지 않으므로 감사합니다.https://stackoverflow.com/questions/12303974/sign-array-to-variable#12304017배열을 재할당하는 방법을 보여 주는 데 사용됩니다. 바라보다 man bash
(https://linux.die.net/man/1/bash) 배열, 확장 및 패턴 대체에 대한 자세한 내용은 (매개변수 확장 아래)
분석하다
Bash는 명령줄 인수를 배열로 넣습니다.$@
q
인용된 문자를 저장합니다.
매개변수 확장에 큰따옴표를 사용하면 ${ ... }
개별 매개변수를 고유한 요소로 보존하고 이를 묶으면 ( )
변수에 배열로 할당할 수 있습니다.
/#/$q
^
매개변수 확장에서 패턴의 시작 부분을 따옴표로 묶은 문자(예: 정규식)로 바꿉니다.
/%/$q
$
매개변수 확장에서 패턴의 끝을 따옴표로 묶은 문자(예: 정규식)로 바꿉니다.
사용 사례: 명령줄에서 MySQL에 이메일 주소 목록을 쿼리합니다.
위의 명령문에는 다른 따옴표 문자를 사용하고, 매개변수 사이에 쉼표를 추가하고, 마지막 쉼표를 제거하는 등 몇 가지 변형이 있습니다. 물론 mysql 호출시 비밀번호를 잘못 입력했습니다. 그러니 나를 고소하세요.
q="'"; t=( "${@/#/$q}" ); u="${t[@]/%/$q,}"; v="u.email in( ${u%,} )"
mysql -uprod_program -h10.90.2.11 -pxxxxxxxxxxxx my_database <<END
select ...
from users u
join ....
where $v # <<<<<<<<<<<<<<<<<< here is where all the hard work pays off :-)
group by user_id, prog_id
;
END