2011-12-03 58 views
3

我有一些冗長的腳本互相調用,我希望它們的輸出更具描述性。這個想法是爲每個腳本定製echo命令,如下所示。bash:重寫echo以在腳本中打印自定義前綴

我的問題是,如何使它不遞歸,使用echo

這是script1.sh

#!/bin/bash 
#Original version: 
#function echo(){ echo $(basename $0 .sh): $1; } 
#Version after fixes 
function echo(){ builtin echo -n "$(basename $0 .sh): ">&2; builtin echo [email protected] ; } 
echo Info 
./script2.sh 

這是script2.sh

#!/bin/bash 
#Original version: 
#function echo(){ echo $(basename $0 .sh): $1; } 
#Version after fixes 
function echo(){ builtin echo -n "$(basename $0 .sh): ">&2; builtin echo [email protected] ; } 
echo Info 
exit 0 

所以輸出應該是:

>./script1.sh 
script1: Info 
script2: Info 

---編輯

獎金:

>./script1.sh 2> /dev/null 
Info 
Info 
+0

'未設置-f echo'應該使用之後你 – IljaBek

+0

也可以把這個函數聲明爲它自己的文件,而'source'入需要它的腳本。 –

回答

9

使用builtin關鍵字:

function echo(){ builtin echo $(basename $0 .sh): $1; } 

這裏的幫助頁面:

$ help builtin 
builtin: builtin [shell-builtin [arg ...]] 
    Execute shell builtins. 

    Execute SHELL-BUILTIN with arguments ARGs without performing command 
    lookup. This is useful when you wish to reimplement a shell builtin 
    as a shell function, but need to execute the builtin within the function. 

    Exit Status: 
    Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is 
    not a shell builtin.. 
+2

+1;但不是'$ 1',最好是寫''$ @「'。 (注意這個函數禁用所有'echo'的特殊功能,比如'-E'和'-n'。) – ruakh

+0

thx,更正於 – IljaBek

+0

@lesmana:很好,就像它被設計來解決這個問題:D謝謝! – IljaBek

0

我想出了I/O重定向作爲解決方案。文章Bash Redirections Using Exec激勵了我。它具有以下含義:

  • 重定向腳本的標準或錯誤輸出,無論哪個命令打印到它,例如,回聲,printf等
  • 沒有重複性的subhells或sourced腳本的工作。
  • 重定向擴展到該腳本正在調用的任何可執行文件,即腳本的下標或源腳本。
  • 可以通過創建多個管道來組成過濾器,其中一個管道將其輸出重定向到下一個管道的輸入中,等等。

在我bash shell腳本我用:

alias start_log_ctx="start_filter_by_pipe_regex 2 s/.*/${0##*/}\(pid=$$\): \0/" 
function start_filter_by_pipe_regex { 
    declare -r a="$(mktemp -u)" #1 
    mknod "$a" p    #2 
    sed <"$a" ">&$1" "$2" &  #3 
    exec "$1">"$a"    #4 
} 

alias stop_log_ctx_by_job="stop_filter_by_pipe_job 2" 
def stop_filter_by_pipe_job { 
    exec "$1">&- #1 
    wait "$2" #2 
} 

在本質上start_log_ctx別名使用sed排隊明智(.*)過濾腳本的I/O是去錯誤輸出(2)並將腳本的基本名稱(${0##*/})和進程ID(pid=$$)加到每行中。該start_filter_by_pipe_regex功能的工作原理如下:

  1. Store的絕對路徑,但不創建(-U)的臨時文件。
  2. 在[1.]的絕對路徑下創建管道。
  3. 開始sed作爲背景中的過濾器(&)。讓它從[2.]的管道讀取(<),並將其標準輸出(>)重定向到作爲參數1給出的文件描述符。將參數爲2.的參數傳遞給sed
  4. 重定向(>)作爲1.參數給出的文件描述符到[2.]的管道。

stop_log_ctx別名關閉錯誤輸出的文件描述符(2),並等待前面開始sed停止。它隱含地在關閉文件描述符時這樣做。 stop_filter_by_pipe_job功能執行以下操作:

  1. 關閉作爲參數1給出的文件描述符,從而停止sed
  2. 等待背景sed確定由作爲參數的bash作業停止。

在我的主要功能開始時,我通常會做一個declare -r a="$(start_log_ctx)"並以stop_log_ctx_by_job "$a"結束。

+0

也可以使用'mkfifo「$ a」'而不是'mknod「$ a」p「。 –

1

builtin只適用於shell內部命令,如echo。我知道原始問題與echo特別相關,但由於這是一個受歡迎的谷歌命中「bash覆蓋功能」,我想我會爲其他命令添加我的解決方案。當我運行ssh時,我正在編寫一個封裝器來更改終端名稱,所以我定義了一個名爲ssh的函數,並且需要從內部調用實際的二進制文件。它可能不是最好的方式,但它的工作要做:

function ssh { 
    $(which ssh) [email protected] 
}