最初の引数を除くすべての引数を処理します(bashスクリプト内)


444

最初の引数がファイル名用に予約されている単純なスクリプトがあり、他のすべてのオプションの引数はスクリプトの他の部分に渡す必要があります。

グーグルを使って私はこのウィキを見つけました、しかしそれは文字通りの例を提供しました:

echo "${@: -1}"

次のように、他に何も動作しません。

echo "${@:2}"

または

echo "${@:2,1}"

端末から「不正な置換」が表示されます。

問題は何ですか?また、bashスクリプトに渡された最初の引数を除くすべてをどのように処理できますか?


21
混乱している他の人を呼び出すために、間違ったシバンが提供されて機能"{@:2}"しなくなったため、上記の正しい答えが一致します。
Guvante 2015年

3
Ubuntuやその他の多くのLinuxではダッシュであるデフォルトのシェルを使用しました。ダッシュでは、「$ {@:-1}」は次のように解釈されます:{parameter:-word}-デフォルト値を使用し、パラメーターが定義されていないかnullの場合はwordを使用します。つまり、ダッシュ「$ {@:-1}」は「$ @」とまったく同じ結果になります。bashを使用するには、スクリプトファイルで次の1行目を使用します。#!/ bin / bash
luart

回答:


659

これを使って:

echo "${@:2}"

次の構文:

echo "${*:2}"

するので、同様に動作しますが、推奨されません@Gordonは既に説明し、使用していること*、それは、スペースを1つの引数として一緒にすべての引数を実行しながら、@ジャム、それらの間の休憩(でも自身がスペースを含む引数のいくつかの場合)。との違いはありませんが、echo他の多くのコマンドでは重要です。


7
私はシバンが悪いことに気づきました:#!/usr/bin/env shそれが問題を抱えていた理由です。私がそのシバンを削除した後、上記の例と同じように、あなたの例はうまく機能します
theta

110
"${@:2}"代わりに使用します-使用*すると、すべての引数がスペースを含む単一の引数として一緒に実行@されますが、それらの間の区切りは保持されます(引数自体にスペースが含まれている場合でも)。との違いは目立ちませんがecho、他の多くの点で重要です。
Gordon Davisson、2012年

2
@GordonDavissonここでの要点は、引数を一緒に実行することです。ファイル名を渡せば、あなたは正しいでしょう。 echoあなたのためにそれらを連結するのに十分寛容です。他のコマンドはあまり良くないかもしれません。どちらか一方だけを使用するのではなく、との違い*@、それぞれをいつ使用するかを学びます。ほぼ同じように使用する必要があります。これが問題になる場合の良い例:$3改行(\n)が含まれている場合、デフォルトの$IFS変数があれば、スペースで置き換えられます。
Zenexer 2013年

1
@ゼネクサー:私が理解しているように、問題は最初の引数を除いてすべてを「スクリプトの他の部分に」渡す方法echoであり、例として使用しただけでした。私の経験では、それらを一緒に実行したいという状況はまれであり(この例については、この質問を参照してください)、"$@"ほとんどの場合、そうしたいです。また、改行で言及する問題は、$@(または$*)が二重引用符で囲まれていない場合にのみ発生します。
ゴードンデイヴィソン2013年

@GordonDavissonうーん...あなたが正しい、今私はそれについて考えています。改行は問題になりません。他のことを考えていたに違いない。ただし、それらを一緒に実行することについてはまだ意見の相違があります。$*スクリプトで頻繁に使用する必要があります。
Zenexer 2013年

180

あなたも/bin/sh試して動作するソリューションが必要な場合

first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"

shift [n]位置パラメータをn回シフトします。A shiftはの値$1をの値に$2、の値$2をの値に$3、というように設定して、の値を$#1つ減らします。


25
+1:シフトする前に、$ 1を変数に保存する必要があります。
グレン

3
驚いたことにfoo=shift、私が期待することをしていません。
キーススマイリー

私はこれが古いことを知っていますが、試してみてくださいfoo=$(shift)
raumaan kidwai

12
@raumaankidwaiこれは2つの理由で機能しません:1)shift(シェル内で)出力がありません。$1すべてを破棄し、すべてを下にシフトします。2)$(...)独自のローカル引数を持つサブシェルを開始します。サブシェルの引数を変更しますが、親には影響しません
Ben Jackson

ありがとう:) somecommand "$1" "${@:2}"この方法で何をする(つまり、「インライン」にシフトする)ための方法はありますか?
匿名


0

何か他のものを探してこれに出くわしました。投稿はかなり古く見えますが、bashでの最も簡単な解決策を以下に示します(少なくともbash 4)set -- "${@:#}"

    #!/bin/bash

    someVar="${1}"
    someOtherVar="${2}"
    set -- "${@:3}"
    input=${@}

    [[ "${input[*],,}" == *"someword"* ]] && someNewVar="trigger"

    echo -e "${someVar}\n${someOtherVar}\n${someNewVar}\n\n${@}"

基本的に、set -- "${@:3}"perlのシフトのように、配列の最初の2つの要素をポップし、3番目を含む残りのすべての要素を保持します。最後の要素をポップオフする方法もあると思います。

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