2011-12-03 63 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] 
}