Error handling 修改zsh命令以转发错误

Error handling 修改zsh命令以转发错误,error-handling,pipe,zsh,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 && xc

我想修改我最近的一个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。当错误列表(保存到剪贴板并回显的内容)不为空时,如何向代码添加修改以设置错误标志?

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


您在评论中明确指出,您没有使用
bash
,而是使用
zsh
。因此,我的解决方案的一些语法必须更改,因为它们以不同的方式处理
PIPESTATUS
变量

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


第一种方法是使用现有别名,如下所示:

makecclip && [ "${pipestatus[1]}" -eq "0" ] && echo "ok"
仅当
“${pipestatus[1]}”等于0(生成期间无错误)时,才会运行
echo
命令

更方便的解决方案是为
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

我试过了,但似乎不起作用。我认为实际上是make改变了pipestatus,但是我也必须重定向错误。它和你的测试一起工作吗?是的,它在我的电脑上工作得很好。我已经编辑了我的问题以添加我使用过的测试。@AdamHunyadi抱歉,我花了一段时间才将我的测试用例形式化为脚本。您可以看到我运行的测试和得到的输出。好的,这就是为什么我指定我的解决方案仅适用于
bash
(因为您的问题带有标签)
bash
zsh
具有不同的内部变量。我会根据上下文修改我的答案。当您从控制台调用它时,它是否失败?从带有
#的脚本/bin/bash
shebang?从带有
#的脚本/bin/zsh
shebang?从这两种情况?