質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
zsh

zshは、UNIX系OSのシェルの1つです。 cshやksn系のコマンドライン編集機能も実装されたシェルです。

Q&A

2回答

938閲覧

zsh: `zparseopts`の`--`,条件文で使われる`${:--}`について

ajifulai

総合スコア0

zsh

zshは、UNIX系OSのシェルの1つです。 cshやksn系のコマンドライン編集機能も実装されたシェルです。

0グッド

1クリップ

投稿2021/07/15 14:56

編集2021/07/22 15:49

前提・実現したいこと

あるシェルスクリプトを見ていて,分からないことが出てまいりまして
どうしても理解できず,質問させて頂くことにしました.

シェルはzshです.

処理としては,
zparseopts コマンドで,コマンドラインオプションのチェックを行っています.

= = = 

コードは後述「該当のソースコード」のセクションに書くとしまして,
該当のコードの箇所を記述しながら進めさせていただきたいと思います.

質問は,大きく2つです.

1) -- とは?

sh

1zparseopts -D -A opthash -- i

オプション -i の解析を行っていると思います.

上述コードで良く分かっていないのが,-- の箇所です.

これは,必ず必要なものなのでしょうか.
そして,必ず最初に指定するべきものなのでしょうか.
この -- の位置づけが,いまひとつ飲み込めておりません.

この -- の意味についてご教示頂ければと思っております.

2) 条件文,そして,どうして,${:--} なのか

該当の箇所になります.;

sh

1for optionCheck in "$@"; 2do 3 if [ ${optionCheck[(i)${:--}]} -eq 1 ]; then 4 ... 5 fi 6done

まず,if 文の条件でして,これが何を評価しているのかが,良く理解できていません.

確かにコマンドラインオプションですと,1,そうでない,普通の引数だと2を返しています.

[${配列名[(i)条件],または,[${連想配列名[(i)キー名]}]のどちらかと思ったのですが,どうもいずれでもないようです.

この if 文は,何を評価しているのでしょうか.

c.f.:
» zsh の配列操作の基本から応用まで - Qiita
» zshの連想配列の使い方まとめ - Qiita

そして,ここではもう一つあります.

条件文にある ${:--} についてです.

これは,${name:-word}の形式のパラメータ展開で,
オプションのハイフン - があるか,で見ているのでしょうが,
${:--}${name:-word} で言いますとname の部分を省略したスタイルで行っているのが
どうしても理解できないでおります.

if [ ${optionCheck[(i)-]} -eq 1 ]; then でも良いのではないか,と思ってしまうのです.

どうして,${:--} のスタイルで評価するのでしょうか.

c.f.
» zshexpn(1): zsh expansion/substitution - Linux man page

発生している問題・エラーメッセージ

上述の通りです.

該当のソースコード

sh

1#!/bin/zsh -eu 2 3local -A opthash 4zparseopts -D -A opthash -- i 5 6if [ -n "${opthash[(i)-i]}" ]; then 7 readonly HAS_OPTIONS="Yes" 8else 9 readonly HAS_OPTIONS="No" 10fi 11 12for optionCheck in "$@"; 13do 14 if [ ${optionCheck[(i)${:--}]} -eq 1 ]; then 15 echo "Specified option is incorrect." 16 exit 1 17 fi 18done

試したこと

  1. について

» zsh: 22 Zsh Modules. 'zparseopts'

» zshで簡単にコマンドライン オプションを解析する - Qiita

  1. について

» zshexpn(1): zsh expansion/substitution - Linux man page 'Parameter Expansion'

sh

1% printf '%s\n' ${:--} 2-

補足情報(FW/ツールのバージョンなど)

sh

1% sw_vers 2sw_vers 3ProductName: Mac OS X 4ProductVersion: 10.15.7 5BuildVersion: 19H15 6% zsh --version 7zsh --version 8zsh 5.8 (x86_64-apple-darwin19.3.0)

稚拙な内容で大変恐縮ではありますが,
ご教示のほど,何卒,よろしくお願いします.

以上です.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

1) -- とは?

-- は zparseopts 自身のオプションと、シェルスクリプトのオプション指定部分を見分ける為の印です。

例えば zparseopts -D -A opthash -- i の場合

  • -D (見つかったオプションを位置パラメータから削除する)
  • -A opthash (オプション解析の結果を連想配列opthashに格納する)

の二つが zparseopts 自身の動作を変えるオプションで、

  • i (シェルスクリプトとして-iオプションを受け付ける)

がオプション指定部分です。

これが、例えば-iではなく--Dをオプションとして受け付けるようにする場合、--を使わないと

zparseopts -D -A opthash -D

となりますが、これだと後ろの-Dはオプション指定ではなく、zparseoptsのオプションだと判断されてしまします。
このような場合に対応する為に、単独の-または--より後ろはzparseoptsのオプションではなくオプション指定として扱うというルールが出来ました。
そしてこのような場合に

zparseopts -D -A opthash -- -D

とする事で後ろの-D--Dオプションを使う為のオプション指定である事が明確になります。

一方、最初の例の場合は--を省略して

zparseopts -D -A opthash i

としてもiがオプション指定部分だという事が明確です。このような場合は---を使わなくても問題ありません。

2) 条件文,そして,どうして,${:--} なのか

まず${:--}ですが、これはお分かりのように常に-に展開されます。
なので${optionCheck[(i)${:--}]}${optionCheck[(i)-]}と同じ意味です。

optionCheckはスカラー値ですが、スカラー値の場合${string[(i)pattern]}は変数stringの中でpatternが現れる場所を返します。(見つからない場合は文字列の長さ+1を返します)
例えばstringの値がabcdeの場合、${string[(i)cd]}3となります。

${optionCheck[(i)${:--}]} -eq 1という条件は、optionCheckの値の中で-の位置が1の時、つまりoptionCheckの値が-で始まっている時という意味になります。

検索するパターンの指定で${:--}を使っている理由はわかりません。
ただ、条件文にしても ${optionCHeck[1]} = "-" などもっと分かりやすい書き方が有るのに回りくどい書き方をしていたり、1)でも必要のない--を使っている辺りからも、スクリプトを書いた人がzshに慣れていなくてよく判らずに書いている気がします。

投稿2021/08/03 02:57

doda

総合スコア947

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自分は zsh についてよく知らないのですが…

zsh

1zparseopts -D -A opthash -- i

これは unix コマンドで一般的に使われるテクニックですが
ハイフン付きの引数をコマンドのオプションと区別したいときに使いますね。
-hogefuga という名前のファイルを消したいときなどに応用できます。
ただ、このコマンドの場合とは若干ちがいがみられるようですね。

zsh

1 if [ ${optionCheck[(i)${:--}]} -eq 1 ]; then

こちらは推測になりますが(手元に zsh 動かせるものがないので)

${optionCheck[(i)x]} は、文字列 $optionCheck 先頭から x を検索して位置を返す
のはいいとして…

${optionCheck[(i)-]} とすると構文エラーとなる、もしくは期待通りの動きにならないので、
配列でリテラル値を指定しているのでは?
エスケープするよりその方がコストがかからないという判断でしょう。

if 文の一部をとりだして実行してみてはいかがでしょうか。

投稿2021/07/17 02:14

編集2021/07/17 02:17
takasima20

総合スコア7464

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ajifulai

2021/07/22 15:38

takasima20さま ありがとうございます. 返事遅くなってしまいました.申し訳ございません. > ハイフン付きの引数をコマンドのオプションと区別したいときに使いますね。 > -hogefuga という名前のファイルを消したいときなどに応用できます。 なるほど, ハイフンで始まる,ファイル名(e.g. -file.txt)ということでしょうか. 例であげました,`zparseopts -D -A opthash -- i`の`i`はオプションだったりします. 自身の書き方が悪かったのかもしれません. 例えば,ですが, 『該当のソースコード』のセクションで記載したスクリプトが,`example.sh`だとして, ターミナルでは,例えば,以下のように記述して実行してます.; ```sh % ./example.sh -i -file.txt ``` としても,動作するようですね. そして,こちら, `if [ ${optionCheck[(i)${:--}]} -eq 1 ]; then`なのですが, `${optionCheck[(i)-]}`としてしまっても, 期待通りの動作するようなのですが... > エスケープするよりその方がコストがかからないという判断でしょう。 こういう考え方からの,`${optionCheck[(i)${:--}]} -eq 1`といった 書き方なのでしょうかね. きっちりとしたルールとか, "こうしなければいけない"と言うものでも無い,というものなのでしょうかね.
takasima20

2021/07/22 20:31

書いた人が几帳面な人なのか、少し勘違いしていたかってとこスかね。
ajifulai

2021/07/23 18:18

ありがとうございます. うーん,その「勘違い」をスッキリさせたいところですが... こういうの面倒臭いだけですかねw
takasima20

2021/07/23 20:25

可能性でいえば、以前のバージョン(zsh)ではできなかったとか?
ajifulai

2021/07/27 01:27

バージョンですか. 意識したことなかったので,
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問