修改zsh命令以转发错误

时间:2016-11-25 11:01:38

标签: error-handling pipe zsh

我想修改我最近的一个Bash别名来转发错误。这是别名:

alias makecclip=
     "make |& tee >(sed \"s,\x1B\[[0-9;]*[a-zA-Z],,g\"  |
     egrep \":[0-9]+:[0-9]+: error\" | cut -d : -f1,2,3 |
     head -n 1 | xargs -0 echo -n | xclip -selection clipboard &&
     xclip -selection clipboard -o)

此代码显示C ++编译的结果,然后删除格式和显示,并将第一个错误位置(如果有)添加到剪贴板。

但是,我想使用这样的代码:

makecclip && bin/someexecutablecreated

这虽然破坏了&&运算符,因为它总是运行bin / someexecutablecreated,即使存在编译错误也是如此。当错误列表(保存到剪贴板并回显的内容)不为空时,如何添加对代码的修改以设置错误标志?

1 个答案:

答案 0 :(得分:1)

您可以使用PIPESTATUS内部变量(此变量在非bash shell中具有其他名称)来解决您的问题。这允许具有管道传递的命令的退出状态的历史记录。

您在评论中对未使用bash进行了预测,但使用了zsh。因此,我的解决方案的一些语法必须改变,因为它们以不同的方式处理PIPESTATUS变量。

在bash中,您使用${PIPESTATUS[0]},而在zsh中使用${pipestatus[1]}

使用现有别名的第一种方法可以如下:

makecclip && [ "${pipestatus[1]}" -eq "0" ] && echo "ok"

仅当echo等于0(make期间没有错误)时才会运行"${pipestatus[1]}"命令

更方便的解决方案是使用函数而不是makecclip的别名。在~/.bashrc文件中,您可以写:

makecclip () {
    make |& tee >(sed "s,\x1B\[[0-9;]*[a-zA-Z],,g" | egrep ":[0-9]+:[0-9]+: error" | cut -d : -f1,2,3 | head -n 1 | xargs -0 echo -n | xclip -selection clipboard && xclip -selection clipboard -o)
    return "${pipestatus[1]}"
}

现在,makecclip && echo "ok"将按预期工作。

测试用例:

#!/bin/zsh
#do not run this test if there is an existing makefile in your current directory
rm -f makefile
makecclip () {
    make |& tee >(sed "s,\x1B\[[0-9;]*[a-zA-Z],,g" | egrep ":[0-9]+:[0-9]+: error" | cut -d : -f1,2,3 | head -n 1 | xargs -0 echo -n | xclip -selection clipboard && xclip -selection clipboard -o)

    # this part is only present to check the pipestatus values during the tests.
    # In the real function, I wrote 'return ${pipestatus[1]}' instead. 
    a=(${pipestatus[@]})
    echo ${a[@]}
    return ${a[1]}
}

echo "# no makefile"
makecclip && echo "ok"
echo -e "\n# empty makefile"
touch makefile
makecclip && echo "ok"
echo -e "\n# dummy makefile entry"
echo -e 'a:\n\t@echo "inside makefile"' > makefile
makecclip && echo "ok"
echo -e "\n# program with error makefile"
echo -e "int main(){error; return 0;}" > target.cc
echo -e 'a:\n\tgcc target.cc' > makefile
makecclip && echo "ok"

输出:

$ ./test.sh
# no makefile
make: *** No targets specified and no makefile found.  Stop.
2 0

# empty makefile
make: *** No targets.  Stop.
2 0

# dummy makefile entry
inside makefile
0 0
ok

# program with error
gcc target.cc
target.cc: In function ‘int main()’:
target.cc:1:12: error: ‘error’ was not declared in this scope
 int main(){error; return 0;}
            ^
makefile:2: recipe for target 'a' failed
make: *** [a] Error 1
target.cc:1:12
2 0