web-dev-qa-db-ja.com

ksh93のタイプセットが期待どおりに機能しない

typesetkshlocalだと思っていましたが、これは_ksh93_で失敗しますが、他のすべてのtypeset対応シェル(bash、 yash、zsh、pdksh)

_#!/bin/ksh -ex

foo(){
    typeset a b
    a=0; b=1
    return
}
a=a; b=b
foo
#confirm that the globals didn't change
[ "$a" = a ] 
[ "$b" = b ]
_

何ができますか?

6
PSkocik

typesetはksh93のprivate(動的スコープを実行するPerlではなく、mylocalのような静的スコープを使用)は、宣言された関数に対してのみです。 ksh関数定義スタイルの使用:

function foo {
  typeset var=whatever
  ...
}

ボーン構文(または.コマンド(ところで、kshスタイルの関数でも使用できます))では、スコープはありません($1$2 ..を除く)。もちろん$#)。したがって、Bourneスタイルの関数を使用して、親コンテキストで値を取得したり、変数の値またはタイプを変更したりできます(ただし、kshスタイルでtypeset -nを使用することもできます)。

Ksh88では、typesetはkshとBourneの両方の関数定義スタイルで動的スコープを実行していました。 David Kornによると、POSIXは、kshの変数スコープが動的(劣っていると見なされる)であることに基づいて指定しなかったため、静的スコープに変更しました。 ksh93(完全な書き換え)の場合。

しかし、その間に、他のシェルは変数スコープを実装し、それらはすべてdynamicスコープを使用してksh88を模倣しました。

zshprivateキーワードが追加され、local/typesetに加えてksh93と同様のスコープを持ち、ksh88

静的スコープと動的スコープの違いを確認するには、以下を比較してください。

"$Shell" -c 'function f { typeset a=1; g; echo "$a"; }
             function g { echo "$a"; a=2; }
             a=0; f'

$Shell == ksh93出力の場合:

0
1

そしてksh88またはbash出力:

1
2

zsh

$ zsh -c 'zmodload zsh/param/private
          f() { private a=1; g; echo $a;}
          g() { echo $a; a=2; }
          a=0; f'
0
1

bashzshksh88ksh93pdkshyashまたはに移植可能なコードでローカルスコープを使用できるようにするにはdash/FreeBSD sh、あなたができること:

[ -n "$BASH_VERSION" ] && shopt -s expand_aliases
alias shdef= kshdef='#'
if type typeset > /dev/null 2>&1; then
  alias mylocal=typeset
  if (a=1; f() { typeset a=2; }; f; [ "$a" = 2 ]); then
    alias shdef='#' kshdef='function'
  fi
else
  alias mylocal=local
fi

そして、関数を次のように宣言します。

kshdef foo
shdef foo()
{
  mylocal var
  var=value
  ...
}

いずれにせよ、さまざまなシェルでのlocalの動作には多くの違いがあります。上記の動的な考慮と静的な考慮のほかに、変数が最初に未設定または空の値を取得するか、親スコープから値を継承するかです。そして、readonly/unsetがキーワードであるか組み込みであるかに関係なく、localtypesetとの相互作用があります(split + glob処理に影響します)...

ksh93でkshスタイルの関数定義を使用することには、他にも影響があります。詳細については、manページを参照してください。

もっと読む

11