Bash-Hackers.orgには、崩壊関数に関する素敵な小さなwikiエントリがあります。基本的に、崩壊関数は、ある条件に基づいてそれ自体を再定義する関数です。基本的な例は次のようなものでした。
chatter() {
if [[ $verbose ]]; then
chatter() {
echo "$@"
}
chatter "$@"
else
chatter() {
:
}
fi
}
これは、次のような関数を作成するのに役立つかもしれないちょっとしたトリックだと思いました。
# a portable extended regular expression sed for Linux and Mac
# simply checks if using an option fails for one version
# @see http://wiki.bash-hackers.org/howto/collapsing_functions
my_sed() {
if ( echo abc | sed -r /abd/p > /dev/null 2>/dev/null ) ; then
#we are running a GNU version. redefine function
echo gnu
my_sed() {
sed -r "$@"
}
else
#we are running another version. defaulting to BSD
#redefining function
echo osx
my_sed() {
sed -E "$@"
}
fi
my_sed "$@"
}
(echoステートメントはデバッグ用です)。my_sed "s/foo/bar" /tmp/somefile.txt
これは、「gnu」(Linuxの場合はosx、Macの場合はosx)を最初に出力し、その後の実行のためにサイレントに保つときに、意図したとおりに機能します。しかし、単にパイプで関数を使用すると、関数は再定義されず、常に「gnu」が出力されます。例:echo 123 | my_sed 's/foo/bar'
シェルで実行されるたびに「gnu」を出力します。
どうしてこれなの?関数が新しい定義を維持できないようにする現在のコンテキスト/シェルで配管は何をしていますか?配管は毎回新しいプロセスをフォークしているので、元のシェルから新しい定義が失われていますか?