bash関数やスクリプトの最後の位置引数をポップするには?

bash関数やスクリプトの最後の位置引数をポップするには?

bash関数またはスクリプトの最後の位置引数を表示する必要があることがよくあります。

「ポップ」とは、「位置引数のリストからそれらを削除し、(オプションで)変数に割り当てます」を意味します。

この作業がどれくらいの頻度で必要かを考えると、私が見つけた最良の結果が以下の例に示されているという事実に少し驚きました。

foo () {
    local argv=( "$@" )
    local last=${argv[$(( ${#argv[@]} - 1 ))]}
    argv=( ${argv[@]:0:$(( ${#argv[@]} - 1 ))} )
    echo "last: $last"
    echo "rest: ${argv[@]}"
}

言い換えれば、何千人もの俳優が参加する大西洋の作品...

もっとシンプルで読みやすいものはありますか?

答え1

(bash 4.2以降)を使用して最後の要素にアクセスし、${argv[-1]}組み込み関数(bash 4.3以降)を使用して配列からその要素を削除できます。unset

last=${argv[-1]}
unset 'argv[-1]'

グローバル演算子argv[-1]と同様に、二重引用符が必要なため、引用符のない引用符は、ファイルが現在のディレクトリに存在する場合は拡張できます(ファイルが存在しないかアクティブでない場合は何もしないかエラーが発生します)。[...]argv[-1]argv-argv1nullglobfailglob

答え2

これはどうですか:

foo () {
    local last="${!#}"
    local argv=("${@:1:$#-1}")
    echo "last: $last"
    echo "rest: ${argv[@]}"
}

答え3

読みやすくするために少し単純化できますが、基本的なアプローチは同じです(サポートされていないBashバージョンがある場合は便利です)。クワジモドの献身):

foo () {
    local argv=( "$@" )
    local last="${argv[$# - 1]}"
    argv=( "${argv[@]:0:$# - 1}" )
    echo "last: $last"
    echo "rest: ${argv[@]}"
}

このように使うのがやや生意気なのは認めます$#が、次のような効果があります。${#argv[@]} この具体例ではそして、コードがより簡潔になりました。

答え4

より簡単に同等の場合bxmの答え、使用set:

pop() {
  last="${!#}"  # see man bash, search for "indirect expansion"
  set -- "${@:1:$#-1}"

  printf 'not last: %s\n' "$@"
  printf 'last: %s\n' "${last}"
}

pop 1 2 3 4
# prints:
# not last: 1
# not last: 2
# not last: 3
# last: 4

ここでは${!#}間接引数拡張(「間接拡張」検索)であり、man bash引数set -- ARGS...$1など)の新しい値を指定された引数に設定します。

${!#}配列スライシングはbashismですが、set --すべてのPOSIXシェルに移植可能であることは注目に値します。

関連情報