シェルスクリプトに渡された最後の引数を取得する


272

$1最初の引数です。
$@それらのすべてです。

シェルスクリプトに渡された最後の引数を見つけるにはどうすればよいですか?


私はbashを使用していましたが、よりポータブルなソリューションの方が優れています。
トーマス


10
useは$ {!#}も使用できます
Prateek Joshi

11
bashの場合のみ、Kevin Littleの答えは単純${!#}です。を使用してテストしbash -c 'echo ${!#}' arg1 arg2 arg3ます。以下のためのbashkshのzshのデニス・ウィリアムソンの答えが提案しています${@: -1}。また${*: -1}、使用することもできます。を使用してテストしzsh -c 'echo ${*: -1}' arg1 arg2 arg3ます。しかし、それはダッシュcshtcshでは機能しません。
olibre 2017

2
${!#}とは異なり${@: -1}、パラメータ展開でも機能します。でテストできbash -c 'echo ${!#%.*}' arg1.out arg2.out arg3.outます。
アーチスタントン

回答:


177

これは少しハックです:

for last; do true; done
echo $last

これも移植性が高く(これもbash、ksh、shで動作するはずです)、引数を変更しないので便利です。

これは、for何をループするかを指示しないと暗黙的に引数をループするという事実と、forループ変数がスコープ指定されていないという事実を使用します。つまり、設定された最後の値を保持します。


10
@MichałŠrajer、私はあなたがコロンではなくコロンを意味したと思う;)
PawełNadolski

2

4
古いSolarisと古いボーンシェル(POSIXではない)では、「for last in "$ @"; do true; done」
mcoolive

8
@mcoolive @LaurenceGolsalves for last in "$@"; do :; doneは、移植性が向上するだけでなく、意図がより明確になります。
エイドリアンGünter18

1
@mcoolive:1979年のUNIX v7ボーンシェルでも動作します。v7shとPOSIX shの両方で実行すると、移植性は向上しません:)
Dominik R

291

これはBashのみです。

echo "${@: -1}"

43
なぜスペースが必要なのか不思議に思う人のために、man bashはこれについてそれを述べています:>:-拡張と混同しないように、負のオフセットは少なくとも1つのスペースでコロンから分離する必要があることに注意してください。
foo 2015年

1
私はこれを使用しており、WindowsのMSYS2 bashでのみ機能します。奇妙な。
Steven Lu

2
注:この回答は、でのみ機能するのとは異なり、すべての Bashアレイで${@:$#}機能し$@ます。で$@新しい配列にコピーするとarr=("$@")${arr[@]:$#}は未定義になります。これは$@"$@"展開に含まれていない0番目の要素があるためです。
Llama氏

@ Mr.Llama:$#Bashでは配列はスパースであり$#、配列内の要素の数が表示されますが、必ずしも最後の要素(またはelement + 1)を指しているわけではないため、配列を反復する場合は、もう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 2013

1
スティーブン、あなたがペナルティボックスに着陸するために何をしたかはわかりませんが、私はここであなたの仕事を愛しています。
Bruno Bronosky 2017

4
はい。単に最高。コマンドと最後の引数を除くすべて ${@: 1:$#-1}
Dyno Fu

1
@DynoFuありがとうございます。私の次の質問に回答しました。したがって、シフトは次のようになります。echo ${@: -1} ${@: 1:$#-1}、最後が最初になり、残りは下にスライドします
マイク

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 14

1
BASH_ARGVには、現在の位置引数のリストではなく、bashが呼び出されたとき(または関数に対して)の引数があります。
アイザック

また、BASH_ARGV得られるのは、単に「最後の値」ではなく、最後に指定された引数であった値です。たとえば、!:単一の引数を指定した場合、shiftを呼び出す${@:$#}と何も生成されません(唯一の引数をシフトアウトしたためです)。ただし、BASH_ARGVその(以前の)最後の引数は引き続き提供されます。
Steven Lu


29

以下はあなたのために働くでしょう。@は引数の配列です。:を意味します。$#は、引数の配列の長さです。したがって、結果は最後の要素です。

${@:$#} 

例:

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

これはbashのみであることに注意してください。


例は関数の場合ですが、スクリプトも同様に機能します。この答えは明確で簡潔なので、気に入っています。
ジョナブラウン

1
そして、それはハッキーではありません。これは、副作用や特殊なqwerksではなく、言語の明示的な機能を使用します。これは受け入れられる答えになるはずです。
musicin3d

25

最後の引数を前のすべての引数から分離しようとしたときにこれが見つかりました。回答のいくつかは最後の引数を取得しますが、他の引数もすべて必要な場合、それらはあまり役に立ちません。これははるかにうまく機能します:

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

これはbashのみであることに注意してください。


3
スティーブン・ペニーの答えは、使用:ビットよりよいです${@: -1}のための最後${@: -2:1}のための最後から二番目(のように...)。例:bash -c 'echo ${@: -1}' prog 0 1 2 3 4 5 6prints 6。この現在のAgileZebraのアプローチを維持するには、を使用${@:$#-1:1}して2番目を取得します。例:bash -c 'echo ${@:$#-1:1}' prog 0 1 2 3 4 5 6prints 5。(そして${@:$#-2:1}3番目のラストを取得するためなど...)
olibre

4
AgileZebraの答えは、最後の引数以外のすべてを取得する方法を提供するので Stevenの答えがそれに取って代わるとは思いません。ただし、$((...))1を減算する理由はないよう${@:1:$# - 1}です。単純にを使用できます。
dkasak

ありがとうdkasak。簡略化を反映して更新されました。
アジャイルゼブラ

22

これはすべてのPOSIX互換シェルで機能します。

eval last=\${$#}

出典:http : //www.faqs.org/faqs/unix-faq/faq/part2/section-12.html


2
以前の同一の回答に添付されたこのコメントを参照してください。
追って通知があるまで一時停止。

1
私がここで目にする最も簡単なポータブルソリューション。これにはセキュリティ上の問題はありません、@ DennisWilliamson。$#任意の文字列に設定する方法がない限り、引用は経験的に正しく行われているようです(そうは思いません)。eval last=\"\${$#}\"また動作し、明らかに正しいです。引用符が不要な理由はわかりません。
Palec 2014年

1
以下のためのbashzshのダッシュkshが eval last=\"\${$#}\"細かいです。ただし、cshおよびtcshの場合はを使用しますeval set last=\"\${$#}\"。次の例を参照してくださいtcsh -c 'eval set last=\"\${$#}\"; echo "$last"' arg1 arg2 arg3
olibre 2017

12

これが私の解決策です:

  • かなり移植可能(すべてのPOSIX sh、bash、ksh、zsh)で動作するはずです
  • 元の引数をシフトしません(コピーをシフトします)。
  • 悪を使わない eval
  • リスト全体を反復しません
  • 外部ツールを使用しない

コード:

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

1
すばらしい答え-短く、持ち運び可能で、安全です。ありがとう!
JANLalinský

2
これは素晴らしいアイデアですが、いくつかの提案があります。最初に引用符を前後に追加する必要が"$1"あります"$#"(この素晴らしい回答unix.stackexchange.com/a/171347を参照してください)。第2に、echo残念ながら移植性がないため(特にの場合-n)、printf '%s\n' "$1"代わりに使用する必要があります。
joki

おかげで@joki私は多くの異なるUNIXシステムで作業しecho -n、どちらも信頼しませんecho "$1"が、失敗するposixシステムについては知りません。とにかく、printf確かに予測可能です-更新されました。
のMichałŠrajer

@MichałŠrajerは、「$ 1」が「-n」または「-」である場合を考慮します。たとえば、ntharg 1 -nまたはntharg 1 --さまざまなシステムで異なる結果をもたらす可能性があります。あなたが今持っているコードは安全です!
joki

10

最も古いソリューションから新しいソリューションへ:

最も移植性の高いソリューションで、さらに古いsh(スペースとグロブ文字を使用)(ループなし、高速):

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

または、変数を設定する場合last

$ 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で動作します。
追って通知があるまで一時停止。

@デニス:いいね!$((...))構文については知りませんでした。
ローレンスゴンサルベス2010

printf '%s\n' "$1"からの予期しない動作を回避するために使用する必要がありますecho(例:)-n
joki

2

非破壊的な方法でそれを行いたい場合、1つの方法はすべての引数を関数に渡し、最後の引数を返すことです。

#!/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
間接参照のためにevalは悪い習慣、そして巨大なセキュリティ上の懸念を(値は、エコーや外部$(に引用されていない)はもちろんのこと、やり過ぎであるバッシュは任意のVARのために、間接参照のための組み込みの構文は次のとおりです。!だから、は、last="${!#}"同じを使用しますより安全でコンパクトな組み込みの
健全

別の答えで同じことを実行するためのより明確な方法を参照してください。
Palec 2014年

@MestreLionの引用符は、のRHSでは必要ありません=
トム・ヘイル

1
@TomHale:の特定のケースではtrueです${!#}が、一般にはありませんlast='two words'。コンテンツにのようなリテラルの空白が含まれている場合は、引用符が引き続き必要です。$()内容に関係なく、空白のみが安全です。
MestreLion

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 2014

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

以下のスクリプトを試して、最後の引数を見つけてください

 # 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

トーマスをチェックしていただきありがとうございます。メンションした#./arguments.sh "最後の値"のようにasスクリプトを実行しようとしました。最後の引数は次のとおりです。#./arguments.sh "doubleを使用した最後の値チェック"最後の引数は次のとおりです: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、

最後の引数が二重引用符で囲まれた文であり、その文が1つの引数であることになっている場合、プレラストは失敗します。
Stephane

0

最近使用したコマンドの最後の引数を返すには、特別なパラメーターを使用します。

$_

このインスタンスでは、別のコマンドが呼び出される前にスクリプト内で使用された場合に機能します。


これは質問が求めているものではありません
retnikt

-1

だけを使用してください!$

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

これは質問が求めているものではありません
retnikt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.