これは、なにをしたくて書いたもの?
Bashで関数の存在確認をする方法を知りたい、ということで。
あくまで対象とするのは「関数」です。
declare -F or type?
Bashのドキュメントのシェル関数の記載を見てみましょう。
Bash Features / Basic Shell Features / Shell Functions
シェル関数は通常のコマンドと同じように実行されます。
They are executed just like a "regular" simple command.
ただ、新しいプロセスが作られるわけではないのが違いですね。
there is no new process created to interpret them.
これを見ると、関数の確認にはdeclareコマンド(一覧は-fオプション、定義は-Fオプション)かtypesetコマンドを使うのが
よさそうです。
The -f option to the declare (typeset) builtin command (see Bash Builtin Commands) lists function names and definitions. The -F option to declare or typeset lists the function names only (and optionally the source file and line number, if the extdebug shell option is enabled).
ちなみにtypesetはdeclareのシノニムということになっています。
The typeset command is supplied for compatibility with the Korn shell. It is a synonym for the declare builtin command.
Bash Features / Shell Builtin Commands / Bash Builtin Commands / typeset
というわけで、今回のお題にはdeclare、それからtypeを使うのがよさそうです。
- Bash Features / Shell Builtin Commands / Bash Builtin Commands / declare
- Bash Features / Shell Builtin Commands / Bash Builtin Commands / type
ちなみに関数の削除はunsetの-fオプションです。
Functions may be exported so that child shell processes (those created when executing a separate shell invocation) automatically have them defined with the -f option to the export builtin (see Bourne Shell Builtins). The -f option to the unset builtin (see Bourne Shell Builtins) deletes a function definition.
少し試してみましょう。
環境
今回の環境はこちら。
$ bash --version GNU bash, バージョン 5.2.21(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2022 Free Software Foundation, Inc. ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. $ apt search ^bats.* ソート中... 完了 全文検索... 完了 bats/noble,noble,now 1.10.0-1 all [インストール済み] bash automated testing system bats-assert/noble,noble,now 2.1.0-3 all [インストール済み] Helper library providing common assertions for Bats bats-file/noble,noble,now 0.4.0-1 all [インストール済み] Helper library providing filesystem-related assertions for Bats bats-support/noble,noble,now 0.3.0-4 all [インストール済み、自動] Supporting library to test bats helper libraries
確認してみる
こんなファイルを用意。
functions.bash
function hello() { echo 'Hello World!!' }
現在のシェルに読み込ませます。
$ source functions.bash
確認。
$ hello Hello World!!
declare -Fで確認してみます。
$ declare -F hello hello $ echo $? 0
なお、declare自体は変数宣言の組み込みコマンドで、-Fオプションをつけて関数名を指定することで、関数名と属性のみを
表示するオプションです。
通常は結果は不要なので、こう使うことになると思います。
$ declare -F hello > /dev/null
存在しない関数に対して実行するとなにも表示されませんし、終了ステータスは1になります。
$ declare -F not_exists_function $ echo $? 1
typeはそのまま実行するとこうなります。
$ type hello hello は関数です hello () { echo 'Hello World!!' }
-tオプションをつけることで、対象がどのようなものであるかを返してくれます。関数の場合はfunctionですね。
$ type -t hello function $ echo $? 0
終了ステータスは0です。
全部でalias、keyword、function、builtin、fileがあります。
$ type -t echo builtin $ type -t gcc file $ type -t grep alias $ type -t if keyword
対象がない場合は、declare -Fと似た挙動になります。
$ type -t not_exists_function $ echo $? 1
if文で使うならこんな感じでしょうか。
if declare -F hello > /dev/null; then echo 'exists hello function' fi if ! declare -F non_exists_function > /dev/null; then echo 'non exists hello function' fi if type -t hello > /dev/null; then echo 'exists hello function' fi if ! type -t non_exists_function > /dev/null; then echo 'non exists hello function' fi
Batsでテストも書いておきました。
test/functions.bats
setup() { bats_load_library bats-support bats_load_library bats-assert DIR=$(cd "$(dirname "$BATS_TEST_FILENAME")" > /dev/null 2>&1 && pwd) # shellcheck disable=SC1091 source "${DIR}/../src/functions.bash" } @test "test declare -F for exists function" { run declare -F hello # 実際に使う場合 # declare -F hello > /dev/null assert_success assert_output "hello" } @test "test declare -F for non exists function" { run declare -F non_exists_function assert_failure 1 assert_output "" } @test "test type -t for exists function" { run type -t hello # 実際に使う場合 # type -t hello > /dev/null assert_success assert_output "function" } @test "test type -t for non exists function" { run type -t non_exists_function assert_failure 1 assert_output "" }