2012-10-15 60 views
2

在Bash-Hackers.org上有關於摺疊功能的nice little wiki entry。基本上,摺疊功能是基於某種條件重新定義自己的功能。基本的例子是類似以下內容:爲什麼管道保持摺疊功能不能保持其新定義?

chatter() { 
    if [[ $verbose ]]; then 
    chatter() { 
     echo "[email protected]" 
    } 
    chatter "[email protected]" 
    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 "[email protected]" 
     } 
    else 
     #we are running another version. defaulting to BSD 
     #redefining function 
     echo osx 
     my_sed() { 
      sed -E "[email protected]" 
     } 
    fi 
    my_sed "[email protected]" 
} 

(回聲聲明只是爲了調試BTW)。這在按照預期運行時以my_sed "s/foo/bar" /tmp/somefile.txt的形式運行,第一次輸出「gnu」(在Linux上,Mac上是osx),然後保持沉默以供後續運行。但是如果我簡單地使用管道中的函數,函數不會被重新定義,而是會不斷輸出「gnu」。例如:echo 123 | my_sed 's/foo/bar'每次在shell中運行時都會輸出「gnu」。

這是爲什麼?什麼是管道處理與當前上下文/外殼,使功能保持其新的定義?是否每次管道都分叉一個新進程,以便新的定義從原始shell中丟失?

回答

5

管道運行在一個子shell中,當子shell退出時重新定義會丟失。

+0

像我那樣。謝謝! – oligofren

+1

如果您使用的是bash 4.2或更高版本(您必須在Mac OS X上升級,因爲它隨附3.2),您可以在第一次調用my_sed之前使用'shopt -s lastpipe',這將會導致管道中的最後一個命令在當前shell中運行,而不是子shell。這可能會解決問題。 – chepner

+0

好的提示,但不幸的是,即使OS X 10.6(2010年發佈)使用2007年(版本3.2.48)的Bash版本...... – oligofren