zsh構文とは何ですか?名前()真

zsh構文とは何ですか?名前()真

次のブロックが関数を表すと仮定しますが、おそらくそうではありません。

mounted()true
if
  ...
fi ... && mounted

この構造が何であるかを理解したいと思います。関数ヘッダーに似た構文が見つかりませんでした。 扱いにくい

実際のコードのより完全なスニペットは次のとおりです。

#! /bin/zsh -p

# leaving out a section...

tmpdir=$(mktemp -d) || exit

mounted()true
if
  mount "$type[@]" -o "${(j[,])opts}" -- "$dev" "$tmpdir"
then
  mount --bind -- "$tmpdir/$subdir" "$dest" || mounted()false
  umount -- "$tmpdir"
fi && rmdir -- "$tmpdir" && mounted

一度理解したら、zshスクリプト全体を私にとってより使いやすい言語に変換します。中間ステップでbashに変換することもできます。

答え1

これは関数定義のためのBourneシェル構文(1980年代)であり、zshに限定されません。

Bourneシェルでは、関数はfunctionName()コマンドの前に貼り付ける方法で定義されます。

name() trueそのため、単純なコマンドで呼び出される関数を本文として定義します。nametrue

$ name()true
$ type name
name is a shell function

これは、ほぼすべてのBourne様シェル(ksh、ash、dash、bosh、pdksh、mksh、zsh ...)の場合です。注目すべき例外の1つはbash²(GNUシェル)です。最初はコマンドグループ{ ...; })は関数の本文になり、後で次のように変更されました。すべての複合コマンド〜のようにPOSIXsh言語要件

したがって、または(およびkshから借りた構文)は複合コマンドとして扱われます。または、bash関数の本文が1つの単純なコマンドのみを含むコマンドのグループです。name()((1))name()[[ . ]](( ... ))[[ ... ]]name() { true; }

ksh構文は異なりますが、これは関数を導入する最初のシェルですfunction name { body; }zshKornとBourneの構文をサポートし、独自の拡張機能があります。

からKornのセクションにリンクされていますzshinfo zsh functionfunctionキーワード関数定義構文。拡張の1つは、zsh同じボディを使用して複数の関数を同時に定義し、任意の文字列を関数名として使用できることです。

vrai 1 + $'\1' () true
faux 0 - $'\0' '' () false

呼び出されたパラメータやパラメータを使用しないいくつかの異なる関数を定義しtrueますfalse

関数名を省略すると、引数を受け入れてその場で呼び出せる匿名関数になります。

() { echo There are $# non-hidden txt files; } *.txt(N)

(明らかな理由で、匿名関数が引数を受け入れるためには、その本文は単純なコマンドにはなりません。)

キーは関数名で、値が本文のコードである特別なzsh連想配列を介しても関数を使用できます。関数を定義する他の方法も同様です。$functionsfunctions[name]=truename


今、ブール値を格納するために関数を使用することは一般的ではありませんが、しばらく停止して考えると意味があります。

たとえば、C言語では、if/while構文または&&/||論理演算子が数値に適用されます。ゼロ以外の数値であればif (condition) something実行します。または、C言語のような言語は、それを定義または空でない文字列に展開します。somethingconditionawkperlcondition

ただし、シェルはすべてのコマンドラインソルバーよりも優先されます。シェルでは、すべてがコマンドです。if/while&&/ は||ほとんどのシェルでコマンドに従って動作します。コマンドが成功するとif condition; then something; fi実行されます。somethingcondition

falseそしてtrue常に失敗/成功するブール定数コマンド(ほとんどのシェルに組み込まれている)なので、ブール値を表す確かなコマンドです。関数は、コマンド(または通常はシェルコード)を格納するのに最適なデータ構造です。

aliases(多くの人がcshを破損した継承と見なし、cshは関数なしのシェル(元のBourneシェルなど)です)は、エイリアスを含むコードを読み取ると拡張され、実行時に拡張されないため、ここでは機能しません。たとえば、

alias name=false
myfunction()
  if name; then
    something
  fi
alias name=true
myfunction

関数が実行されるのではなく、関数を定義するコードを読み取るとエイリアスが拡張されるため、関数の本文がif false; then...実際に含まれます。name

コードは関数の代わりに変数に保存できます。

name=true name=false
if eval " $name"; then
  ...
fi

4evalでコードを説明するコマンドが成功したかどうかをテストします。この場合、空または未定義の結果が発生します(オプションを除く)。$namenounset$name本物

それともこれを行うことができます(これは私が通常sh/スクリプトbashでやっていることです):

name=true name=false
if "$name"; then
  ...
fi

$name引数なしでコマンドに保存された名前を実行する場所です。

または:

name=(true) name=(false)
if "${name[@]}"; then
  ...
fi

パラメータを保存する場所簡単なコマンド$name 大量に変わりやすい。

[Cに似た言語操作に精通している人は、ブール値を整数変数として保存し、/ etcなどのコマンドを実行したり、テキスト表現から変換してtest整数expr値をテストしたりできます。

false=0 true=1
name=$false name=$true

if expr "$name" > /dev/null; then
  ...
fi
if [ "$name" -ne 0 ]; then
  ...
fi

Kornに似たシェル(bashおよび含む)では、Cに似た算術式を評価し、ゼロ以外の数値(NaNを含む)が生成されたときに成功を返す構文をzsh使用できます。((...))

false=0 true=1
name=$false name=$true
# or even:
name=false name=true
if (( name )); then
  ...
fi

また、コマンドを実行して文字列を比較したり(たとえば[// testagain)、expr他のKorn[[ string = pattern ]]同様の構成などのパターンマッチングを実行したりできます。

name=true name=false
if [ "$name" = true ]; then
  ...
fi

(これはCで作業するのと同じくらい私にとって不均一ですif (strcmp(name, "true") == 0)...。)

あるいは、必要に応じて、すでに定義されている変数に対してawk/などのテストを実行することもできます。perl

unset -v name # unset = false
name=         #   set = true
if [ -n "${name+true}" ]; then
  ...
fi

1 Bourneシェル(レプリケーション/派生5ではない)にバグがありますが、関数の本文にリダイレクトを含む単純なコマンドを使用すると機能しません。これがおそらくPOSIXで複合コマンドのみが必要な理由です。関数本体としてサポートされています。

² yash(POSIX仕様に従って書かれています)poshpdksh標準に準拠していることを確認するのに役立つように書かれているため、それらを含む標準へのほとんどの拡張は削除されます)は、他の2つの例外です。

³これは、ファイルに任意の文字列を含めることができるため、外部コマンドとコマンド引数が任意の文字列である可能性があるという事実と一致します(ただし、ファイル名は空白にできず、ファイル名/引数にはNULバイトを含めることはできません)。 Bourneシェルでは、関数と変数名は同じ名前空間を共有します(同じ名前の関数と変数は定義できません)、関数名には変数名と同じ制限があります。

4一部の実装ではオプションの終わり表示をサポートevalしていないため、精度のために先行スペースを追加しました。--

5 zsh自体には、関数の本文でリダイレクトを使用するときに独自の問題がありましたが、ほとんどが解決されました。しかし、今でも文書に明確に示されているようにf() { cmd; } < $1(本文がリダイレクトを持つコマンドグループである特別な場合)、関数のスコープを参照せずに$1POSIX標準に準拠しないようにする呼び出し元の対応するインスタンスを参照します。 。これは、単純なコマンドや他の種類の複合コマンド(内部的に含まれています)には適用されません。$1$1zsh{...}

関連情報