쉘 스크립트에 전달 된 마지막 인수 얻기


272

$1첫 번째 주장입니다.
$@그들 모두입니다.

쉘 스크립트에 전달 된 마지막 인수를 어떻게 찾을 수 있습니까?


나는 bash를 사용하고 있었지만 휴대용 솔루션이 많을수록 좋습니다.
토마스


10
use도 사용할 수 있습니다 $ {! #}
Prateek Joshi

11
에만 해당 배쉬케빈 리틀의 대답은 간단을 제안한다 ${!#}. 를 사용하여 테스트하십시오 bash -c 'echo ${!#}' arg1 arg2 arg3. 들어 bash는 , KSHzsh을데니스 윌리엄슨의 대답은 제안한다 ${@: -1}. 또한 ${*: -1}사용할 수 있습니다. 를 사용하여 테스트하십시오 zsh -c 'echo ${*: -1}' arg1 arg2 arg3. 그러나 dash , cshtcsh 에서는 작동하지 않습니다 .
올리버

2
${!#}와 달리 ${@: -1}매개 변수 확장에서도 작동합니다. 로 테스트 할 수 있습니다 bash -c 'echo ${!#%.*}' arg1.out arg2.out arg3.out.
아치 스탠턴

답변:


177

이것은 약간의 해킹입니다.

for last; do true; done
echo $last

이것은 또한 이식성이 뛰어나며 (다시 말해서, bash, ksh 및 sh와 함께 작동해야 함) 인수를 이동시키지 않으므로 멋질 수 있습니다.

for루프 오버 대상을 알려주지 않으면 인수 를 암시 적으로 반복한다는 사실과 루프 변수의 범위가 지정되지 않았다는 사실을 사용합니다. 설정된 마지막 값을 유지합니다.


10
) MichałŠrajer @, 난 당신이 대장이 아닌 쉼표 의미 생각
파블 Nadolski


4
구본 쉘 (POSIX가 아님)이있는 구 솔라리스에서 ""@에 마지막으로 쓰십시오; 사실을 수행하십시오. "
mcoolive

8
@mcoolive @LaurenceGolsalves 휴대 성이 뛰어나고 for last in "$@"; do :; done의도도 훨씬 명확 해졌습니다.
Adrian Günter

1
@mcoolive : 그것은 심지어 1979 년의 유닉스 v7 bourne 쉘에서도 작동합니다. v7 sh와 POSIX sh 모두에서 실행된다면 더 이식성이 없습니다 :)
Dominik R

291

이것은 배쉬 전용입니다.

echo "${@: -1}"

43
왜 나에게 공간이 필요한지 궁금해하는 사람들을 위해 man bash는 이에 대해 다음과 같이 말하고 있습니다.> :-확장과 혼동되지 않도록 음수 오프셋을 최소한 하나의 공백으로 분리해야합니다.
foo

1
나는 이것을 사용하고 있으며 Windows에서만 MSYS2 bash에서 중단됩니다. 기괴한.
Steven Lu

2
참고 : 이 답변은 모든 Bash 배열에 ${@:$#}대해서만 작동합니다 $@. 복사 인 경우 $@로 새로운 배열 arr=("$@"), ${arr[@]:$#}정의되지 않은 것입니다. 확장에 $@포함되지 않은 0 번째 요소 가 있기 때문 "$@"입니다.
Mr. Llama

@ Mr.Llama : 피할 수있는 또 다른 장소 $#는 배열을 반복 할 때 Bash에서 배열이 희박하고 배열 $#의 요소 수를 표시하지만 반드시 마지막 요소 (또는 요소 + 1)를 가리키는 것은 아닙니다. 다시 말해, 인덱스 값으로 무언가를해야하는 경우 인덱스 for ((i = 0; i++; i < $#)); do something "${array[$i]}"; done를 수행하지 말고 대신 for element in "${array[@]}"; do something "$element"; done반복하거나 인덱스를 반복 해서는 안됩니다 for index in "${!array[@]}"; do something "$index" "${array[$index]}"; done.
추후 공지가있을 때까지 일시 중지되었습니다.

80
$ set quick brown fox jumps

$ echo ${*: -1:1} # last argument
jumps

$ echo ${*: -1} # or simply
jumps

$ echo ${*: -2:1} # next to last
fox

공백은 기본값으로 해석되지 않도록 필요 합니다 .

이것은 bash 전용입니다.


9
가장 좋은 대답은 마지막 인수 옆에 포함되기 때문입니다. 감사!
e40

1
스티븐, 네가 페널티 박스에 착륙 한 게 뭔지 모르겠지만 난 네 일이 너무 좋아
Bruno Bronosky

4
예. 그냥 최고. 명령과 마지막 논쟁을 제외하고 ${@: 1:$#-1}
Dyno Fu

1
@DynoFu 감사합니다. 다음 질문에 대답하셨습니다. 따라서 교대는 다음과 같이 보일 수 있습니다 : echo ${@: -1} ${@: 1:$#-1}, 마지막이 먼저되고 나머지는 아래로 내려갑니다
Mike

73

bash 3.0 이상에 대한 가장 간단한 대답은

_last=${!#}       # *indirect reference* to the $# variable
# or
_last=$BASH_ARGV  # official built-in (but takes more typing :)

그게 다야.

$ cat lastarg
#!/bin/bash
# echo the last arg given:
_last=${!#}
echo $_last
_last=$BASH_ARGV
echo $_last
for x; do
   echo $x
done

출력은 다음과 같습니다

$ lastarg 1 2 3 4 "5 6 7"
5 6 7
5 6 7
1
2
3
4
5 6 7

1
$BASH_ARGVbash 함수 내에서 작동하지 않습니다 (내가 잘못하지 않는 한).
Big McLargeHuge

1
BASH_ARGV에는 현재 위치 인수 목록이 아닌 bash가 호출 될 때 (또는 함수에) 인수가 있습니다.
Isaac

또한 BASH_ARGV당신을 산출하는 것은 단순히 "마지막 값"이 아니라 마지막으로 주어진 값이었습니다. 예를 들어! : 하나의 단일 인수를 제공하면 shift를 호출 ${@:$#}하고 아무 것도 생성하지 않습니다 (단 하나의 인수 만 이동했기 때문에). 그러나 BASH_ARGV이전의 마지막 인수는 여전히 제공합니다.
Steven Lu


29

다음은 당신을 위해 일할 것입니다. @는 인수 배열입니다. : 의미합니다. $ #는 인수 배열의 길이입니다. 결과는 마지막 요소입니다.

${@:$#} 

예:

function afunction{
    echo ${@:$#} 
}
afunction -d -o local 50
#Outputs 50

이것은 bash 전용입니다.


예제는 함수를위한 것이지만 스크립트도 같은 방식으로 작동합니다. 나는 명확하고 간결하기 때문에이 답변을 좋아합니다.
Jonah Braun

1
그리고 해키되지 않습니다. 부작용이나 특수한 쿼크가 아닌 언어의 명시적인 기능을 사용합니다. 이것은 정답입니다.
musicin3d

25

마지막 인수를 이전의 모든 인수와 분리하려고 할 때 이것을 찾았습니다. 일부 답변은 마지막 인수를 얻지 만 다른 모든 인수가 필요한 경우 큰 도움이되지 않습니다. 이것은 훨씬 잘 작동합니다.

heads=${@:1:$#-1}
tail=${@:$#}

이것은 bash 전용입니다.


3
스티븐 페니의 대답은 사용 : 비트 좋네요 ${@: -1}을위한 마지막${@: -2:1}에 대한 마지막에서 두 번째 (등등 ...). 예 : bash -c 'echo ${@: -1}' prog 0 1 2 3 4 5 6인쇄합니다 6. 이 현재 AgileZebra의 접근 방식을 유지하려면을 사용 ${@:$#-1:1}하여 마지막 두 번째 를 얻으십시오 . 예 : bash -c 'echo ${@:$#-1:1}' prog 0 1 2 3 4 5 6인쇄합니다 5. (그리고 마지막 세 번째${@:$#-2:1}을 얻기 위해 ...)
올리버

4
AgileZebra의 답변 은 마지막 인수를 제외한 모든 인수 를 얻는 방법을 제공 하므로 Steven의 답변이 그것을 대체한다고 말할 수는 없습니다. 그러나 $((...))1을 빼는 데 사용할 이유가없는 것 같습니다 ${@:1:$# - 1}. 간단히 사용할 수 있습니다 .
dkasak

고마워요. 단순화를 반영하여 업데이트되었습니다.
AgileZebra

22

이것은 모든 POSIX 호환 쉘에서 작동합니다.

eval last=\${$#}

출처 : http://www.faqs.org/faqs/unix-faq/faq/part2/section-12.html


2
이전의 동일한 답변에 첨부 된 이 의견을 보십시오 .
추후 공지가있을 때까지 일시 중지되었습니다.

1
가장 간단한 휴대용 솔루션입니다. 이 문자열에는 보안 문제가 없습니다. @DennisWilliamson $#은 임의의 문자열 로 설정하는 방법이 없다면 인용문을 경험적으로 올바르게 수행하는 것 같습니다 (그렇지 않다고 생각합니다). eval last=\"\${$#}\"또한 작동하고 분명히 맞습니다. 따옴표가 왜 필요하지 않은지 보지 마십시오.
Palec

1
들어 배쉬 , zsh을 , 대시KSH eval last=\"\${$#}\" 괜찮습니다. 그러나 cshtcsh의 경우 eval set last=\"\${$#}\". 이 예를 참조하십시오 : tcsh -c 'eval set last=\"\${$#}\"; echo "$last"' arg1 arg2 arg3.
올리버

12

내 솔루션은 다음과 같습니다.

  • 꽤 이식성 (모든 POSIX sh, bash, ksh, zsh)이 작동해야합니다.
  • 원래 인수를 이동하지 않습니다 (사본을 이동).
  • 악을 사용하지 않습니다 eval
  • 전체 목록을 반복하지 않습니다
  • 외부 도구를 사용하지 않습니다

암호:

ntharg() {
    shift $1
    printf '%s\n' "$1"
}
LAST_ARG=`ntharg $# "$@"`

1
좋은 대답-짧고 휴대 가능하며 안전합니다. 감사!
Ján Lalinský

2
이것은 좋은 생각이지만, 나는 몇 가지 제안이있다 : 첫째로 모두 주위를 추가해야 인용 "$1"하고 "$#"(이 위대한 응답 참조 unix.stackexchange.com/a/171347을 ). 둘째, echo슬프게도 이식 할 수 -n없으므로 (특히 ) printf '%s\n' "$1"대신 사용해야합니다.
joki

@joki 덕분에 많은 다른 유닉스 시스템에서 일했고 신뢰할 echo -n수는 없지만 posix 시스템에 대해서는 알지 echo "$1"못합니다. 어쨌든 printf실제로 더 예측 가능합니다-업데이트되었습니다.
Michał Šrajer

그래서 예를 들면, "-"MichałŠrajer @ "$ 1"은 "-n"또는 인 경우를 고려 ntharg 1 -n하거나 ntharg 1 --여러 시스템에서 서로 다른 결과를 얻을 수 있습니다. 지금 가지고있는 코드는 안전합니다!
joki

10

가장 오래된 솔루션부터 새로운 솔루션까지 :

가장 오래된 솔루션 sh(공백 및 glob 문자와 함께 작동) (루프 없음, 더 빠름) :

eval printf "'%s\n'" "\"\${$#}\""

bash 버전 2.01부터

$ set -- The quick brown fox jumps over the lazy dog

$ printf '%s\n'     "${!#}     ${@:(-1)} ${@: -1} ${@:~0} ${!#}"
dog     dog dog dog dog

ksh, zsh 및 bash의 경우 :

$ printf '%s\n' "${@: -1}    ${@:~0}"     # the space beetwen `:`
                                          # and `-1` is a must.
dog   dog

그리고 "다음까지":

$ printf '%s\n' "${@:~1:1}"
lazy

printf를 사용하여 대시 (예 :)로 시작하는 인수 관련 문제를 해결하십시오 -n.

모든 쉘과 구형 sh(공백 및 글로브 문자로 작동)의 경우 :

$ set -- The quick brown fox jumps over the lazy dog "the * last argument"

$ eval printf "'%s\n'" "\"\${$#}\""
The last * argument

또는 lastvar 를 설정하려면 다음을 수행하십시오 .

$ eval last=\${$#}; printf '%s\n' "$last"
The last * argument

그리고 "다음까지":

$ eval printf "'%s\n'" "\"\${$(($#-1))}\""
dog



3
shift `expr $# - 1`
echo "$1"

인수의 수에서 1을 뺀 수만큼 인수를 이동시키고 마지막 인수가 될 첫 번째 (및 유일한) 나머지 인수를 리턴합니다.

나는 bash에서만 테스트했지만 sh 및 ksh에서도 작동해야합니다.


11
shift $(($# - 1))-외부 유틸리티가 필요하지 않습니다. Bash, ksh, zsh 및 dash에서 작동합니다.
추후 공지가있을 때까지 일시 중지되었습니다.

@ 데니스 : 좋은! 나는 $((...))구문 에 대해 몰랐다 .
Laurence Gonsalves

printf '%s\n' "$1"예기치 않은 동작을 피하기 위해 사용하려고합니다 echo(예 :) -n.
joki

2

비파괴적인 방식으로 수행하려면 한 가지 방법은 모든 인수를 함수에 전달하고 마지막 인수를 반환하는 것입니다.

#!/bin/bash

last() {
        if [[ $# -ne 0 ]] ; then
            shift $(expr $# - 1)
            echo "$1"
        #else
            #do something when no arguments
        fi
}

lastvar=$(last "$@")
echo $lastvar
echo "$@"

pax> ./qq.sh 1 2 3 a b
b
1 2 3 a b

실제로 상관 하지 않으면 다른 인수를 유지하는 것에 쓰지 않는다면 함수에 필요하지 않지만 다른 인수가 이미 처리되지 않은 한 다른 인수를 유지하고 싶지 않은 상황을 생각하기가 어렵습니다. 이 경우 순차적으로 처리하는 process / shift / process / shift / ... 방법을 사용합니다.

나는 당신 순차적 인 방법을 따르지 않았기 때문에 그것들을 유지하고 싶다고 가정합니다 . 이 메소드는 또한 인수가없는 경우를 처리하여 ""를 리턴합니다. 주석 처리 된 else절 을 삽입하여 해당 동작을 쉽게 조정할 수 있습니다 .


2

tcsh의 경우 :

set X = `echo $* | awk -F " " '{print $NF}'`
somecommand "$X"

나는 이것이 과제를 제외하고 휴대용 솔루션 일 것이라고 확신합니다.


나는 당신이 이것을 영원히 게시 한 것을 알고 있지만,이 솔루션은 훌륭합니다-누군가가 tcsh를 게시하게되어 기쁩니다!
user3295674

2

@AgileZebra의 답변 (및 @starfry의 의견)이 가장 유용하다는 것을 알았지 만 heads스칼라로 설정 되었습니다. 배열이 더 유용 할 것입니다.

heads=( "${@:1:$(($# - 1))}" )
tail=${@:${#@}}

이것은 bash 전용입니다.


헤드를 배열로 어떻게 변환합니까?
Stephane

괄호를 추가하여 이미 수행했습니다. 예를 들어 echo "${heads[-1]}"의 마지막 요소 를 인쇄합니다 heads. 아니면 뭔가 빠졌습니까?
EndlosSchleife

1

다음을 사용하는 솔루션 eval:

last=$(eval "echo \$$#")

echo $last

7
간접 참조에 대한 평가는 나쁜 관행, 그리고 거대한 보안 문제를 (말할 것도없고, 잔인한 값입니다하지 인용에서 에코 또는 외부 $ () 배쉬 어떤 VAR에 대한 간접 참조를위한 내장 구문이 있습니다. !그래서이 last="${!#}"같은를 사용합니다 . 접근 방식이 훨씬 안전하고, 소형, 내장, 제정신 방식 (간접 $ #에 대한 참조) 그리고 적절하게 인용했다.
MestreLion

다른 답변 에서 동일한 작업을 수행하는 더 확실한 방법을 참조하십시오 .
Palec

RHS에는 @MestreLion 따옴표가 필요하지 않습니다 =.
Tom Hale

1
@TomHale :의 경우에 해당 ${!#}하지만 일반적으로 그렇지는 않습니다. 컨텐츠에 리터럴 공백이 포함 된 경우 따옴표가 여전히 필요합니다 ( 예 :) last='two words'. $()내용에 관계없이 공백 만 안전합니다.
MestreLion 2016 년

1

위의 답변을 읽은 후 PGM.cpp에서 g ++를 실행하여 실행 가능한 이미지 PGM을 생성하는 Q & D 셸 스크립트 (sh 및 bash에서 작동해야 함)를 작성했습니다. 명령 행의 마지막 인수는 파일 이름 (.cpp는 선택 사항)이고 다른 모든 인수는 옵션이라고 가정합니다.

#!/bin/sh
if [ $# -lt 1 ]
then
    echo "Usage: `basename $0` [opt] pgm runs g++ to compile pgm[.cpp] into pgm"
    exit 2
fi
OPT=
PGM=
# PGM is the last argument, all others are considered options
for F; do OPT="$OPT $PGM"; PGM=$F; done
DIR=`dirname $PGM`
PGM=`basename $PGM .cpp`
# put -o first so it can be overridden by -o specified in OPT
set -x
g++ -o $DIR/$PGM $OPT $DIR/$PGM.cpp

1

다음은 LAST현재 환경을 변경하지 않고 마지막 인수로 설정 됩니다.

LAST=$({
   shift $(($#-1))
   echo $1
})
echo $LAST

다른 인수가 더 이상 필요하지 않고 이동할 수있는 경우 다음과 같이 단순화 할 수 있습니다.

shift $(($#-1))
echo $1

이식성의 이유로 다음을 수행하십시오.

shift $(($#-1));

다음으로 대체 할 수 있습니다.

shift `expr $# - 1`

$()우리 는 또한 따옴표로 대체 :

LAST=`{
   shift \`expr $# - 1\`
   echo $1
}`
echo $LAST

1
echo $argv[$#argv]

내 답변이 게시하기에 너무 짧았으므로 텍스트를 추가해야합니다. 편집 할 텍스트를 더 추가해야합니다.


어떤 쉘에서 작동합니까? 강타하지 않습니다. (이 물고기 아니 $argv하지만이 $#argv- $argv[(count $argv)]물고기에서 작동).
Beni Cherniavsky-Paskin

1

이것은 내 복사 기능의 일부입니다.

eval echo $(echo '$'"$#")

스크립트에서 사용하려면 다음을 수행하십시오.

a=$(eval echo $(echo '$'"$#"))

설명 (가장 먼저 중첩 됨) :

  1. $(echo '$'"$#")반환하는 $[nr]경우 [nr]매개 변수의 수입니다. 예를 들어 문자열 $123(확장되지 않음).
  2. echo $123 평가시 123 번째 매개 변수의 값을 리턴합니다.
  3. eval$123매개 변수 값으로 확장 됩니다 (예 :) last_arg. 이것은 문자열로 해석되어 반환됩니다.

2015 년 중반 Bash와 함께 작동합니다.


eval 접근법은 이미 여러 번 제시되었지만, 이것의 작동 방식에 대한 설명이 있습니다. 더 개선 될 수는 있지만 여전히 가치가 있습니다.
Palec

0
#! /bin/sh

next=$1
while [ -n "${next}" ] ; do
  last=$next
  shift
  next=$1
done

echo $last

인수가 빈 문자열이면 실패하지만 99.9 %의 경우 작동합니다.
토마스

0

마지막 스크립트를 찾으려면 아래 스크립트를 사용해보십시오

 # cat arguments.sh
 #!/bin/bash
 if [ $# -eq 0 ]
 then
 echo "No Arguments supplied"
 else
 echo $* > .ags
 sed -e 's/ /\n/g' .ags | tac | head -n1 > .ga
 echo "Last Argument is: `cat .ga`"
 fi

산출:

 # ./arguments.sh
 No Arguments supplied

 # ./arguments.sh testing for the last argument value
 Last Argument is: value

감사.


나는 이것이 ./arguments.sh "마지막 값"으로 실패 할 것이라고 생각한다
Thomas

Thomas를 확인 해주셔서 감사합니다. 나는 여러분과 같은 스크립트를 수행하려고 노력했습니다. # ./arguments.sh "이중 값으로 마지막 값 확인"마지막 인수는 다음과 같습니다 : double
Ranjithkumar T

문제는 마지막 논거가 가치가 아니라 '마지막 가치'라는 것이다. 공백이 포함 된 인수로 인해 오류가 발생합니다.
토마스

0

이 작업을 수행하는 훨씬 더 간결한 방법이 있습니다. bash 스크립트에 대한 인수는 배열로 가져올 수 있으므로 요소 처리가 훨씬 간단 해집니다. 아래 스크립트는 항상 스크립트에 전달 된 마지막 인수를 인쇄합니다.

  argArray=( "$@" )                        # Add all script arguments to argArray
  arrayLength=${#argArray[@]}              # Get the length of the array
  lastArg=$((arrayLength - 1))             # Arrays are zero based, so last arg is -1
  echo ${argArray[$lastArg]}

샘플 출력

$ ./lastarg.sh 1 2 buckle my shoe
shoe

0

매개 변수 확장 사용 (일치하는 시작 삭제) :

args="$@"
last=${args##* }

마지막 전에도 쉽게 얻을 수 있습니다.

prelast=${args% *}


마지막 인수에 공백이없는 경우에만 작동합니다.
Palec

마지막 인수가 큰 따옴표로 묶은 문장 인 경우 사전 문장이 실패하며, 해당 문장이 하나의 인수로 가정됩니다.
Stephane

0

가장 최근에 사용한 명령의 마지막 인수를 반환하려면 특수 매개 변수를 사용하십시오.

$_

이 경우 다른 명령이 호출되기 전에 스크립트 내에서 사용되면 작동합니다.


이것은 질문이 아니다
retnikt

-1

그냥 사용하십시오 !$.

$ mkdir folder
$ cd !$ # will run: cd folder

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