注: 以下は、特に明記されている場合を除き、すべての主要な POSIX 互換シェルに適用されます: bash
、dash
、ksh
、およびzsh
。( dash
、Debian Almquist シェルは、sh
Ubuntu などの Debian ベースの Linux ディストリビューションのデフォルト シェル ( ) です)。
unset
本来の意味を持つこと(オプションでシェル関数を-f
定義解除できるビルトイン) は、他のシェル キーワード、コマンド、またはビルトインが本来の意味を持つことを保証するための鍵です。
- 変更されていない から始めて、変更されていないおよび/または
unset
を確保できます。これらを一緒に使用して、シェル キーワード、ビルトイン、および外部ユーティリティを隠す可能性のあるエイリアスまたはシェル関数をバイパスまたは未定義にすることができます。shopt
command
- 関数を未定義にする代わりに、環境を通じて、コードの外部で定義されている可能性のあるものを含め、関数をバイパス
command
するために使用できます。関数のエクスポートは、サポートのみであり、これらのメカニズムの1 つにすぎません。異なるシェルには異なるシェルがあり、複数をサポートする場合があります - 以下を参照してください。
bash
、 、およびPOSIX 互換モードの場合のみdash
、再定義されていないことが保証されます。ksh
bash
unset
悲しいことに、私の知る限りではzsh
、またbash
のデフォルト モードでも、それ自体が再定義されていないことを保証する方法はなくunset
、同様に動作する POSIX ライクなシェルが他にもある可能性があります。
\unset
それを(名前の一部を引用して)呼び出すと、エイリアスの再定義はバイパスされますが、関数の再定義はバイパスされません。元に戻すには、元の自体が必要になりunset
ます:catch 22.
したがって、実行環境を制御できないため、改ざんの影響を完全に受けないシェル スクリプトは作成できません。dash
ksh
bash
追加情報:
POSIX に従って、コマンド名の任意の部分 (例: ) を引用すると、エイリアス形式またはキーワード形式 ( POSIX および用語の予約語\unset
) はその名前でバイパスされますが、シェル関数はバイパスされません。zsh
POSIX ごとに、すべてのエイリアスunalias -a
を定義解除します。すべての関数の定義を解除するための同等の POSIX 準拠のコマンドはありません。
- 警告: 古い
zsh
バージョンはサポートしていません-a
。v5.0.8
ただし、少なくとも現在はそうです。
Builtinは、 、、および- のcommand
キーワード、エイリアス、関数をバイパスするために使用できます。つまり、組み込みと外部ユーティリティのみを実行します。対照的に、デフォルトではbuiltinsもバイパスします。ビルトインも実行するには、を使用します。 bash
dash
ksh
command
zsh
zsh
options[POSIX_BUILTINS]=on
以下は、すべてのシェルで名前付きのみの外部ユーティリティを実行するために使用でき
ます。<name>
"$(command which <name>)" ...
which
コマンド形式の優先順位:
bash
, zsh
: エイリアス > シェル キーワード > シェル関数 > 組み込み > 外部ユーティリティ
ksh
, dash
: シェル キーワード > エイリアス > シェル関数 > 組み込み > 外部ユーティリティ
- つまり、in
bash
とzsh
エイリアスはシェル キーワードをオーバーライドできますが、inksh
とエイリアスはdash
できません。
bash
、ksh
、およびzsh
- すべてではありませんが、POSIX 準拠の形式の代わりにdash
、非標準の関数シグネチャ を使用できます。function <name> { ...
<name>() { ...
- 構文は、次の
function
前提条件です。
- 関数が定義される前に
<name>
、それ自体がエイリアス展開の対象にならないようにします。
- シェルキーワード
<name>
でもある aを選択できること。
このような関数は、引用符で囲まれた形式でのみ呼び出すことができることに注意してください。例: 。
\while
- ( の場合
ksh
、構文を使用すると、さらにステートメントがローカル変数を作成function
することを意味します。)typeset
dash
、ksh
、およびbash
POSIX モードの場合は、特別なビルトイン (例: 、unset
、break
、set
)の命名関数を追加で防止しshift
ます。POSIX 定義の特別なビルトインのリストはここにあります。両方ともdash
、ksh
再定義できないものをさらにいくつか追加します (例: local
in dash
;typeset
およびunalias
in ksh
) が、両方のシェルには、再定義できる特別ではない追加のビルトイン(例: ) があります。
上記の場合、構文が使用されているかどうかに関係なく、ルールが適用されることに注意してください。type
ksh
function
コードの範囲内の環境シェル関数の潜在的なソース:
注: これらを防ぐ最も簡単な方法は、ビルトインまたは外部ユーティリティを呼び出したいときはいつでも(変更されていない)command
ビルトインを使用することです (ビルトインzsh
のバイパスも防止するために)。options[POSIX_BUILTINS]=on
POSIX では、環境変数の絶対パスで指定されたスクリプトを対話型シェル用ENV
にソースすることが義務付けられています(いくつかの制限があります -仕様を参照してください)。常にそれを尊重しますが、v4.2+ では;として or として呼び出された場合にのみそうします。対照的に、この変数を尊重することはありません。ksh
dash
bash
sh
--posix
zsh
- 注:スクリプトとして実行されるコードは、通常、非対話型シェルで実行されますが、それは保証されていません。たとえば、インタラクティブスクリプトからコードを取得したり、誰かがスクリプトを呼び出して
sh -i
インタラクティブ インスタンスを強制したりすることができます。
bash
2 つのメカニズムがあります。
- orを使用して個々の関数をエクスポートする(他のシェルは変数のエクスポートのみをサポートします)
export -f
declare -fx
- 非対話型シェルがオプションの環境変数で開始されるたびに、source へのスクリプトのフル パスを指定します
BASH_ENV
。
ksh
オプションの環境変数を介した関数の自動ロードをサポートします。FPATH
指定されたディレクトリにある関数定義を含むファイルFPATH
は、暗黙的かつ自動的にロードされます。
- (も
zsh
サポートしていFPATH
ますが、自動ロード関数には明示的な autoload <name>
ステートメントが必要です。そのため、指定された名前で関数を自動ロードするように特に要求しない限り、関数はシェルに追加されません。)
zsh
は、その初期化ファイルを介して、任意の zsh
インスタンス (インタラクティブかどうかに関係なく)のソース スクリプトをサポートします。/etc/zshenv
~/.zhsenv
(環境を介して関数を定義するためのメカニズムdash
をサポートしていないようです。)
の回避策:が元の意味を持っているbash
ことを確認します。unset
この回避策は、 がスクリプトを実行することがわかっている場合にのみ安全ですがbash
、残念ながらそれ自体は保証できません。
また、シェル環境を変更する (エイリアスと関数の削除) ため、ソース化するように設計されたスクリプトには適していません。
前述のように、通常、コードを Bash の POSIX 互換モードで実行することは望ましくありませんが、関数によってシャドウされないようにするために一時的に有効にすることができます。unset
#!/bin/bash
# *Temporarily* force Bash into POSIX compatibility mode, where `unset` cannot
# be shadowed, which allows us to undefine any `unset` *function* as well
# as other functions that may shadow crucial commands.
# Note: Fortunately, POSIXLY_CORRECT= works even without `export`, because
# use of `export` is not safe at this point.
# By contrast, a simple assignment cannot be tampered with.
POSIXLY_CORRECT=
# If defined, unset unset() and other functions that may shadow crucial commands.
# Note the \ prefix to ensure that aliases are bypassed.
\unset -f unset unalias read declare
# Remove all aliases.
# (Note that while alias expansion is off by default in scripts, it may
# have been turned on explicitly in a tampered-with environment.)
\unalias -a # Note: After this, \ to bypass aliases is no longer needed.
# Now it is safe to turn POSIX mode back off, so as to reenable all Bash
# features.
unset POSIXLY_CORRECT
# Now UNDEFINE ALL REMAINING FUNCTIONS:
# Note that we do this AFTER switching back from POSIX mode, because
# Bash in its default mode allows defining functions with nonstandard names
# such as `[` or `z?`, and such functions can also only be *unset* while
# in default mode.
# Also note that we needn't worry about keywords `while`, `do` and `done`
# being shadowed by functions, because the only way to invoke such functions
# (which you can only define with the nonstandard `function` keyword) would
# be with `\` (e.g., `\while`).
while read _ _ n; do unset -f "$n"; done < <(declare -F)
# IN THE REST OF THE SCRIPT:
# - It is now safe to call *builtins* as-is.
# - *External utilities* should be invoked:
# - by full path, if feasible
# - and/or, in the case of *standard utilities*, with
# command -p, which uses a minimal $PATH definition that only
# comprises the locations of standard utilities.
# - alternatively, as @jarno suggests, you can redefine your $PATH
# to contain standard locations only, after which you can invoke
# standard utilities by name only, as usual:
# PATH=$(command -p getconf PATH)
# Example command:
# Verify that `unset` now refers to the *builtin*:
type unset
テスト コマンド:
上記のコードがscript
現在のディレクトリのファイルに保存されたとします。
unset
次のコマンドは、 がエイリアスと関数の両方によってシャドウされ、 filescript
がsourcedである改ざんされた環境をシミュレートします。これにより、関数が認識され、対話的にソースされると、エイリアスも展開されます。
$ (unset() { echo hi; }; alias unset='echo here'; . ./script)
unset is a shell builtin
type unset
出力unset is a shell builtin
は、関数とビルトインをシャドウするエイリアスの両方unset
が非アクティブ化されたことの証拠です。