답변:
"$@"
모든 인수를 나타내는 데 사용하십시오 .
for var in "$@"
do
echo "$var"
done
각 인수를 반복하여 별도의 줄에 인쇄합니다. $ @는 인용 부호 안에 공백이있는 경우 인수가 올바르게 분류된다는 점을 제외하고는 $ *처럼 동작합니다.
sh test.sh 1 2 '3 4'
1
2
3 4
"$@"
위치 매개 변수가 없으면 아무것도 확장하지 않고 "$*"
빈 문자열로 확장하면 인수가없는 것과 빈 인수가 다른 것입니다. ${1:+"$@"} in
/ bin / sh`를 참조하십시오 .
$var
인수를 실행할 수있었습니다.
shift
버리고 $1
모든 후속 요소를 아래로 이동합니다.
Robert Gamble 의 간결한 답변은 질문을 직접 처리합니다. 이것은 공백을 포함하는 파일 이름의 일부 문제를 증폭시킵니다.
기본 논문 : "$@"
정확하고 $*
(인용되지 않은) 거의 항상 잘못되었습니다. 이 때문입니다 "$@"
작품의 벌금 인수는 공백을 포함 할 때와 동일하게 작동 $*
그렇지 않은 경우입니다. 어떤 상황에서는 "$*"
괜찮습니다. 그러나 "$@"
대개는 아니지만 항상 같은 장소에서 작동합니다. 인용 부호, $@
및 $*
상응하는 (그리고 거의 항상 잘못)입니다.
그래서, 차이 무엇인가 $*
, $@
, "$*"
, 그리고 "$@"
? 그것들은 모두 '쉘에 대한 모든 주장'과 관련이 있지만 다른 일을합니다. 인용 부호로 둘러싸이지 않은, 때 $*
와 $@
같은 일을한다. 각 '단어'(공백이 아닌 순서)를 별도의 인수로 취급합니다. 인용 된 형식은 상당히 다릅니다 "$*"
. 인수 목록을 공백으로 구분 된 단일 문자열로 "$@"
취급하지만 인수는 명령 줄에 지정했을 때와 거의 동일하게 취급합니다.
"$@"
위치 인수가 없으면 전혀 확장되지 않습니다. "$*"
빈 문자열로 확장합니다. 예, 차이가 있지만 인식하기가 어렵습니다. (비표준) 명령을 도입 한 후 아래에서 자세한 정보를 참조하십시오 al
.
2 차 논문 : 공백이있는 인수를 처리 한 다음 다른 명령으로 전달해야하는 경우 비표준 도구가 필요할 수 있습니다. (또는 배열을주의해서 사용해야합니다 .와 "${array[@]}"
유사 하게 동작합니다 "$@"
.)
예:
$ mkdir "my dir" anotherdir
$ ls
anotherdir my dir
$ cp /dev/null "my dir/my file"
$ cp /dev/null "anotherdir/myfile"
$ ls -Fltr
total 0
drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 my dir/
drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 anotherdir/
$ ls -Fltr *
my dir:
total 0
-rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 my file
anotherdir:
total 0
-rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 myfile
$ ls -Fltr "./my dir" "./anotherdir"
./my dir:
total 0
-rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 my file
./anotherdir:
total 0
-rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 myfile
$ var='"./my dir" "./anotherdir"' && echo $var
"./my dir" "./anotherdir"
$ ls -Fltr $var
ls: "./anotherdir": No such file or directory
ls: "./my: No such file or directory
ls: dir": No such file or directory
$
왜 작동하지 않습니까? 쉘이 변수를 확장하기 전에 따옴표를 처리하기 때문에 작동하지 않습니다. 따라서 쉘에 포함 된 따옴표에주의를 기울이려면 다음 $var
을 사용해야합니다 eval
.
$ eval ls -Fltr $var
./my dir:
total 0
-rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 my file
./anotherdir:
total 0
-rw-r--r-- 1 jleffler staff 0 Nov 1 14:55 myfile
$
" He said,
"Don't do this!"
"(따옴표와 큰 따옴표 및 공백 포함)와 같은 파일 이름이있는 경우 실제로 까다로워집니다 .
$ cp /dev/null "He said, \"Don't do this!\""
$ ls
He said, "Don't do this!" anotherdir my dir
$ ls -l
total 0
-rw-r--r-- 1 jleffler staff 0 Nov 1 15:54 He said, "Don't do this!"
drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 anotherdir
drwxr-xr-x 3 jleffler staff 102 Nov 1 14:55 my dir
$
쉘 (모두)은 그런 것들을 다루기가 쉽지 않기 때문에 많은 유닉스 프로그램은 잘 다루지 못한다. Unix에서 파일 이름 (단일 구성 요소)은 슬래시 및 NUL을 제외한 모든 문자를 포함 할 수 있습니다 '\0'
. 그러나 쉘은 경로 이름의 어느 곳에도 공백이나 줄 바꿈 또는 탭을 권장하지 않습니다. 표준 유닉스 파일 이름에 공백 등이 포함되어 있지 않은 이유도 있습니다.
공백과 다른 까다로운 문자가 포함될 수있는 파일 이름을 다룰 때는 매우주의해야하며, 오래 전에 유닉스에서 표준이 아닌 프로그램이 필요하다는 것을 알았습니다. 나는 그것을 호출합니다 escape
(버전 1.1은 1989-08-23T16 : 01 : 45Z입니다).
다음은 escape
SCCS 제어 시스템과 함께 사용중인 예입니다 . delta
(think check-in ) 및
get
(think check-out )을 모두 수행하는 커버 스크립트입니다 . 다양한 인수, 특히 -y
(변경 한 이유)에는 공백과 줄 바꿈이 포함됩니다. 스크립트는 1992 년부터 사용되므로 $(cmd ...)
표기법 대신 백틱을
사용 #!/bin/sh
하고 첫 번째 줄 에는 사용하지 않습니다 .
: "@(#)$Id: delget.sh,v 1.8 1992/12/29 10:46:21 jl Exp $"
#
# Delta and get files
# Uses escape to allow for all weird combinations of quotes in arguments
case `basename $0 .sh` in
deledit) eflag="-e";;
esac
sflag="-s"
for arg in "$@"
do
case "$arg" in
-r*) gargs="$gargs `escape \"$arg\"`"
dargs="$dargs `escape \"$arg\"`"
;;
-e) gargs="$gargs `escape \"$arg\"`"
sflag=""
eflag=""
;;
-*) dargs="$dargs `escape \"$arg\"`"
;;
*) gargs="$gargs `escape \"$arg\"`"
dargs="$dargs `escape \"$arg\"`"
;;
esac
done
eval delta "$dargs" && eval get $eflag $sflag "$gargs"
(요즘에는 escape를 너무 철저하게 사용하지 않을 것입니다. -e
예를 들어 인수 와 함께 필요 하지는 않지만 전반적으로 이것은을 사용하는 간단한 스크립트 중 하나입니다 escape
.)
escape
프로그램은 단순히 오히려 같은 인수를 출력 echo
하지 않습니다하지만 인수가 사용하기 위해 보호되도록
eval
(한 단계 eval
; I 원격 쉘 실행했던 프로그램이 어떻게, 그리고 출력을 탈출해야한다는 escape
).
$ escape $var
'"./my' 'dir"' '"./anotherdir"'
$ escape "$var"
'"./my dir" "./anotherdir"'
$ escape x y z
x y z
$
나는 al
한 줄에 하나씩 인수를 나열하는 또 다른 프로그램을 가지고 있습니다 (그리고 1987-01-27T14 : 35 : 49의 버전 1.1). 스크립트를 디버깅 할 때 명령 줄에 연결하여 실제로 어떤 인수가 명령에 전달되는지 확인할 수 있으므로 가장 유용합니다.
$ echo "$var"
"./my dir" "./anotherdir"
$ al $var
"./my
dir"
"./anotherdir"
$ al "$var"
"./my dir" "./anotherdir"
$
[ 추가 :
이제 다양한 "$@"
표기법 의 차이점을 보여주기 위해 여기에 또 하나의 예가 있습니다.
$ cat xx.sh
set -x
al $@
al $*
al "$*"
al "$@"
$ sh xx.sh * */*
+ al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file
He
said,
"Don't
do
this!"
anotherdir
my
dir
xx.sh
anotherdir/myfile
my
dir/my
file
+ al He said, '"Don'\''t' do 'this!"' anotherdir my dir xx.sh anotherdir/myfile my dir/my file
He
said,
"Don't
do
this!"
anotherdir
my
dir
xx.sh
anotherdir/myfile
my
dir/my
file
+ al 'He said, "Don'\''t do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file'
He said, "Don't do this!" anotherdir my dir xx.sh anotherdir/myfile my dir/my file
+ al 'He said, "Don'\''t do this!"' anotherdir 'my dir' xx.sh anotherdir/myfile 'my dir/my file'
He said, "Don't do this!"
anotherdir
my dir
xx.sh
anotherdir/myfile
my dir/my file
$
명령 줄 *
과 */*
명령 줄 사이에 원래 공백이 유지되지 않습니다 . 또한 다음을 사용하여 셸에서 '명령 줄 인수'를 변경할 수 있습니다.
set -- -new -opt and "arg with space"
' -new
', ' -opt
', ' and
'및 ' arg with space
'의 4 가지 옵션이 설정 됩니다.
]
흠, 그것은 꽤 긴 대답입니다 . 아마도 주석 이 더 나은 용어 일 것입니다. escape
요청시 제공되는 소스 코드 (gmail dot com에서 이름으로 성으로 이메일 전송). 의 소스 코드 al
는 매우 간단합니다.
#include <stdio.h>
int main(int argc, char **argv)
{
while (*++argv != 0)
puts(*argv);
return(0);
}
그게 다야. test.sh
Robert Gamble이 보여준 스크립트 와 동일 하며 쉘 함수로 작성할 수 있습니다 (그러나 쉘 함수는 처음 썼을 때 Bourne 쉘의 로컬 버전에는 존재하지 않았습니다 al
).
또한 al
간단한 쉘 스크립트로 작성할 수 있습니다 .
[ $# != 0 ] && printf "%s\n" "$@"
인수가 전달되지 않은 경우 출력을 생성하지 않도록 조건이 필요합니다. 이 printf
명령은 형식 문자열 인수 만있는 빈 줄을 생성하지만 C 프로그램은 아무 것도 생성하지 않습니다.
Robert의 대답은 정확 sh
하며 잘 작동 합니다. 훨씬 더 단순화 할 수 있습니다.
for i in "$@"
다음과 같습니다.
for i
즉, 당신은 아무것도 필요하지 않습니다!
테스트 ( $
명령 프롬프트 임) :
$ set a b "spaces here" d
$ for i; do echo "$i"; done
a
b
spaces here
d
$ for i in "$@"; do echo "$i"; done
a
b
spaces here
d
나는 Kernighan과 Pike의 Unix Programming Environment 에서 이것에 대해 처음 읽었습니다 .
에서 다음 bash
을 help for
문서화하십시오.
for NAME [in WORDS ... ;] do COMMANDS; done
경우
'in WORDS ...;'
존재하지 않는, 다음'in "$@"'
가정한다.
"$@"
의미가 무엇인지 알아야 for i
하며, 의미 가 무엇인지 알면 쉽게 읽을 수 for i in "$@"
있습니다.
for i
그것이 키 입력을 저장하기 때문에 더 낫다고 주장하지 않았다 . 나는의 가독성을 비교 for i
하고 for i in "$@"
.
간단한 경우에는을 사용할 수도 있습니다 shift
. 인수 목록을 대기열처럼 취급합니다. 각각 shift
은 첫 번째 인수를 버리고 나머지 인수 각각의 인덱스는 감소합니다.
#this prints all arguments
while test $# -gt 0
do
echo "$1"
shift
done
shift
for 루프에서 수행하면 해당 요소는 여전히 배열의 일부이지만 shift
예상대로 작동 하기 때문에이 대답이 더 좋습니다 .
echo "$1"
인수 문자열의 값에서 간격을 유지하기 위해 사용해야 합니다. 또한 (사소한 문제) 이것은 파괴적입니다. 인수를 모두 이동시킨 경우에는 인수를 재사용 할 수 없습니다. 종종 문제가되지 않습니다. 어쨌든 인수 목록을 한 번만 처리하면됩니다.
--file myfile.txt
$ 1은 매개 변수이고 $ 2는 값이며 다른 인수를 건너 뛰어야 할 경우 shift를 두 번 호출합니다.
예를 들어 모든 요소를 반복하지 않으려는 경우 배열 요소로 액세스 할 수도 있습니다
argc=$#
argv=("$@")
for (( j=0; j<argc; j++ )); do
echo "${argv[j]}"
done
./my-script.sh param1 "param2 is a quoted param"
:-argv = ($ @)를 사용하면 [param1, param2]가 표시됩니다.-argv = ( "$ @")를 사용하면 [param1, param2는 인용 된 매개 변수입니다.]
baz의 답변을 증폭하여 인덱스로 인수 목록을 열거 해야하는 경우 (예 : 특정 단어 검색) 목록을 복사하거나 변경하지 않고도이 작업을 수행 할 수 있습니다.
인수 목록을 이중 대시 ( "-")로 분할하고 대시 앞의 인수를 한 명령에 전달하고 대시 뒤의 인수를 다른 명령에 전달한다고 가정하십시오.
toolwrapper() {
for i in $(seq 1 $#); do
[[ "${!i}" == "--" ]] && break
done || return $? # returns error status if we don't "break"
echo "dashes at $i"
echo "Before dashes: ${@:1:i-1}"
echo "After dashes: ${@:i+1:$#}"
}
결과는 다음과 같아야합니다.
$ toolwrapper args for first tool -- and these are for the second
dashes at 5
Before dashes: args for first tool
After dashes: and these are for the second
getopt 스크립트에서 명령을 사용하여 명령 행 옵션 또는 매개 변수를 형식화하십시오.
#!/bin/bash
# Extract command line options & values with getopt
#
set -- $(getopt -q ab:cd "$@")
#
echo
while [ -n "$1" ]
do
case "$1" in
-a) echo "Found the -a option" ;;
-b) param="$2"
echo "Found the -b option, with parameter value $param"
shift ;;
-c) echo "Found the -c option" ;;
--) shift
break ;;
*) echo "$1 is not an option";;
esac
shift