web-dev-qa-db-ja.com

スクリプト内からコマンドライン引数としてスペースを含む文字列を渡す

Macでbashシェルを使用しています。

実行するようなシェルスクリプト「gac」を書きたい

> gac one two three

実行時と同じ効果exactlyを生成します

> git add .
> git commit -m "one two three"

これまでのところ私のスクリプトはこれです:

function gac() {
    git add .
    concatenated="'$*'"
    git commit -m "$concatenated"
}

シェル引数をスペースで区切られた単一の文字列(スクリプトの2行目) here に連結するトリックを見つけました。上記のスクリプトはほとんど機能しますが、ログメッセージには

a382806 'one two three'

代わりにシェルスクリプトを使用すると

a382806 one two three

手動で入力したときのように

> git commit -m "one two three"

コマンドラインで。

何か案は?

2
Labrador

二重引用符展開 の周りに配置すると( パラメータ展開$*など)、展開されたテキストは対象外となります- 単語分割 。 (これが$展開の周りに二重引用符を使用する理由の1つです。もう1つは globbing を防ぐためです。)さらに、二重引用符内では 一重引用符 は使用できません特別に扱われるため、クォートは行われず、 削除 ではありません。

したがって、 Michael Homerが言う のように、偽の''マークを省略するだけで、関数は機能するはずです。次のように書くことをお勧めします。

gac() {
    git add .
    git commit -m "$*"
}

functionキーワードを使用してBashで関数を定義できますが、上記の構文は同様に機能し、Bourneスタイルのシェル間で移植可能です。


ここで概念的な問題にさらに直接対処するには、元のコードの次の行で、値にスペースが含まれているパラメーターを、gitに単一の引数として渡すことができるように展開することを示しています。

    concatenated="'$*'"

スペースを含む単一の引数を自分で書く場合、スペースを引用符で囲みます。通常、文字列全体を引用符で囲みます。その行に'' inside the ""があると、その引用符を含めようとしていたことがわかります通常は入力します。

このアプローチが機能しない理由は、シェル自体があなたの引用を解釈するものです。これらは通常、シェルから実行するコマンドに対して何も意味しません。次のコマンドがあるとします。

some-command 'foo bar' baz

このコマンドは、実際にはsome-commandコマンドに引用符を渡しません。代わりに、some-commandfoo bar as argument 1として実行し、bazを引数2として実行します(プログラムにその方法を伝える引数0もあります。が実行されました。シェルはsome-commandを渡します。)

引用符を使用すると、シェルに引数の開始と終了を伝えることができます。スペースは通常、シェルに両側のテキストを個別の引数として扱うように指示します1が、シェルにとってスペースの特別な意味を抑制したいのです。引用符が引用されている場合、''の内側の""のように、 their の特別な意味も削除されます。次に、それらはクォートを実行しませんが、代わりにgitがログに示すように、文字通りコマンドに渡されます:

a382806 'one two three'

1シェルの操作では 、スペースおよびタブは、テキストを2つの関連するが異なる方法で別々の単語に分割します。最初に、 コマンドが最初に解析されるとき 、引用符で囲まれていないスペースとタブが字句トークンを区切ります。その他 メタ文字 もこれを行いますが、追加の効果があります-たとえば、;は行を複数のコマンドに分割します。次に、 パラメータ展開 または他の シェル展開$で示されます2 引用符で囲まれていないコンテキストで実行されると、結果はすぐに 単語分割 の対象になります。これは $IFSの文字を区切り文字として使用します です。 IFSのデフォルト値 は、スペース、タブ、改行の順です。

2 または、``構文の代わりに$()構文が使用されている場合でも、 コマンド置換

8
Eliah Kagan