Bash脚本,使用给定字符串

时间:2017-12-12 12:55:29

标签: bash shell unix

让我们假设我有一个类似下面的bash脚本:

#!/bin/bash
echo "start"
do something
git merge blah blah
ant build.xml blah blah blah
echo "end"

显然,git和ant命令的输出与任何其他echo一样包含在bash输出中。

有没有办法实现以下目标?

start
i'm doing something
[GIT] git command output
[GIT] git command output
[GIT] git command output
[GIT] git command output
[ANT] ant command output
[ANT] ant command output
[ANT] ant command output
[ANT] ant command output
[ANT] ant command output
end

如果有一个伟大的人会有解决方案,那么即使一点也不那么重要,我还有一个小问题。

如果线路太长,我还可以拆分命令输出吗? 这样可以避免像

这样的事情
[ANT] ant command output too long command output too long command output too
long command output too long command output too long
[ANT] ant command output
[ANT] ant command output

我认为你注意到我试图整理我的shell的输出,它们是通过Jenkins启动的,并由一个groovy管道脚本生成。

@Yoory& @ghoti:

谢谢两位,答案很可爱!

这个功能很棒,但遗憾的是我整合起来有点困难,因为它必须与其他两个东西互动,这使得它有点难以阅读和混淆。在确切的代码下方,对不起,如果我之前没有提出:

git merge --no-ff origin/module 2>&1 | tee -a /merge_files/merge.log
if [ "${PIPESTATUS[0]}" -ne "0" ];
then
    something
else
    other to do..
fi

@Yoory 当我尝试集成该函数时,将它放在git命令之前,即使git合并失败,PIPESTATUS总是返回0,我确定找到解决方案并不困难,但是你可以看到我对bash并不熟练。

所以现在我使用简单的sed:| sed' s / ^ / [GIT] /'或者sed' s / ^ / [ANT] /' 我试图整合fmt,简单地用悲伤的方式管它。

command | fmt -w 20 | sed "s/^/[ANT] /"

问题在于它适用于具有普通句子的日志,但是对于没有空格分隔符的长字符串(例如路径)它不起作用看起来fmt不会像我使用的那样打破它,i& #39;我看着这个男人找到一个可以帮助我的参数,但是我觉得我到现在为止都无法实现它。

我确实设法让它与fmt合作,但折叠为我带来了魔力!

 command | fold -w 138 | sed "s/^/[ANT] /" 

感谢大家的帮助,如果您想添加任何反馈,我希望听到它们,代码和学习!

3 个答案:

答案 0 :(得分:5)

首先想到的解决方案是:

function prefix_output {
    local prefix=$1
    prefix=${prefix^^}
    "${@}" 2>&1 | while read -r line; do
        printf "[%s] %s\n" "${prefix}" "${line}"
    done
    return ${PIPESTATUS[0]}
}

使用这种方式:

prefix_output git merge blah blah
prefix_output ant build.xml blah blah blah

此外,更新版本现在尊重已执行命令的返回状态。以下内容适用:

prefix_output git merge blah blah && echo success || echo failure

要解决包装太长的行,有一个使用fmt的修改版本(受其他人的答案启发):

function prefix_output {
    local prefix=$1
    prefix=${prefix^^}
    "${@}" 2>&1 | fmt -w 80 | while read -r line; do
        printf "[%s] %s\n" "${prefix}" "${line}"
    done
    return ${PIPESTATUS[0]}
}

我已经在简单的命令上测试过它,告诉我它是否适用于一些更复杂的情况。

答案 1 :(得分:3)

这是Yoory卓越功能的变体:

function prefix {
    local prefix="${1##*/}"             # strip leading path
    prefix=${prefix^^}                  # use upper case
    while read -r line; do              # read lines...
        printf "[%s] %s\n" "${prefix}" "${line}"
    done < <("${@}" 2>&1 | fmt -w 42)   # wrap at 42 columns
}

示例输出:

$ prefix /bin/echo {1..31}
[ECHO] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
[ECHO] 18 19 20 21 22 23 24 25 26 27 28 29 30 31

答案 2 :(得分:2)

  1. 这是一个简短的小功能,它使用pastefmtbash打印命令的前5个字母,(不是这样的 超出标签的宽度),后跟缩进的 60 字符 包装该命令的输出:

    indent_command() { paste <(echo "[${1:0:5}]") <($@ | fmt -w 60) ; }
    

    使用具有各种无限输出的yes进行演示,并head来限制 的是:

    for f in yes no maybe ; do indent_command yes $f | head -3 ; done
    

    输出:

    [yes]   yes yes yes yes yes yes yes yes yes yes yes yes yes yes
            yes yes yes yes yes yes yes yes yes yes yes yes yes yes
            yes yes yes yes yes yes yes yes yes yes yes yes yes yes
    [yes]   no no no no no no no no no no no no no no no no no no no
            no no no no no no no no no no no no no no no no no no no
            no no no no no no no no no no no no no no no no no no no
    [yes]   maybe maybe maybe maybe maybe maybe maybe maybe maybe
            maybe maybe maybe maybe maybe maybe maybe maybe maybe
            maybe maybe maybe maybe maybe maybe maybe maybe maybe maybe
    

    此变体使indent_command前缀为命令名称 大写,只重新格式化长行:

    indent_command() { n="$1" n="${n^^}"; 
                       paste <(echo "[${n:0:5}]") <($@ | fmt -sw 60) ; }
    

    输出变为:

    [YES]   yes
            yes
            yes
    [YES]   no
            no
            no
    [YES]   maybe
            maybe
            maybe
    
  2. GNU sed方法,在每一行使用前缀,以及基于字符的包装, (削减中间的单词):

    indent_with_sed() { $@ | sed -E 's/(.{0,60})/['"${1^^}"'] \1/g;
                                     s/(.)(\['"${1^^}"'] )/\1\n\2/g' ; }
    

    示例:

    indent_with_sed echo foo{1..30}
    

    输出:

    [ECHO] foo1 foo2 foo3 foo4 foo5 foo6 foo7 foo8 foo9 foo10 foo11 foo
    [ECHO] 12 foo13 foo14 foo15 foo16 foo17 foo18 foo19 foo20 foo21 foo
    [ECHO] 22 foo23 foo24 foo25 foo26 foo27 foo28 foo29 foo30