訳あって Zsh を使うことになり、手持ちの Bash 資産を Zsh に対応させていた時のこと。下記のようなコードでハマった。
test.sh:
my_dirname() {
local path=$1
dirname "$path"
}
my_dirname "$@"
% zsh test.sh /path/to/file
my_dirname:2: command not found: dirname
Zsh 使いの人にとって、きっとこれは FAQ なのだろうな。Zsh の path 変数は特殊変数なので、path を書き換えることは PATH を書き換えることに等しい。しかしこれは Zsh 初心者の私にとっては完全に盲点だった。そもそも小文字の変数が特殊変数になるという発想がない。お陰で解決に 3 週間かかった。:-/
他にどういう特殊変数があるかは、man zshparam | grep -F '<S>' すれば分かるっぽい。それにしても path とか status とか、これらの変数名が使えないのは私には窮屈でしょうがない。正直これだけでも、私が Zsh を使いたくない理由になる。
% man zshbuiltins
<...snip...>
typeset [ {+|-}AHUaghlmrtux ] [ {+|-}EFLRZip [ n ] ]
[ + ] [ name[=value] ... ]
typeset -T [ {+|-}Uglrux ] [ {+|-}LRZp [ n ] ]
[ + | SCALAR[=value] array[=(value ...)] [ sep ] ]
typeset -f [ {+|-}TUkmtuz ] [ + ] [ name ... ]
Set or display attributes and values for shell parameters.
<...snip...>
-h Hide: only useful for special parameters (those marked
`<S>' in the table in zshparam(1)), and for local parame‐
ters with the same name as a special parameter, though
harmless for others. A special parameter with this at‐
tribute will not retain its special effect when made lo‐
cal. Thus after `typeset -h PATH', a function containing
`typeset PATH' will create an ordinary local parameter
without the usual behaviour of PATH. Alternatively, the
local parameter may itself be given this attribute; hence
inside a function `typeset -h PATH' creates an ordinary
local parameter and the special PATH parameter is not al‐
tered in any way. It is also possible to create a local
parameter using `typeset +h special', where the local
copy of special will retain its special properties re‐
gardless of having the -h attribute. Global special pa‐
rameters loaded from shell modules (currently those in
zsh/mapfile and zsh/parameter) are automatically given
the -h attribute to avoid name clashes.
どうやら typeset -h を使うと、特殊変数をローカル変数で隠せるようだ。このときエラー出力を捨てれば、Bash にも対応できる。
test2.sh:
my_dirname() {
typeset -h path 2>/dev/null
local path=$1
dirname "$path"
}
my_dirname "$@"
% zsh test2.sh /path/to/file
/path/to
もしスクリプト全体で path を特殊変数として使わないと決められるなら、typeset -h をグローバルに置けば良い。逆に Bash を全く気にしないのであれば、「local -h path=...」と 1 行で書ける。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。