Bash脚本捕获错误

Bash脚本捕获错误,bash,error-handling,Bash,Error Handling,我对bash脚本非常陌生,在我的第一次脚本尝试中,我将文件提交到同一服务器中教授的dropbox 代码如下: #! /bin/bash echo "Submit Lab$1? \c" read choice if [ $choice = "y" ]; then echo "Sending to Prof's dropbox..." cp -r /path/to/lab$1 /path/to/dropbox else echo "Submission terminated."

我对bash脚本非常陌生,在我的第一次脚本尝试中,我将文件提交到同一服务器中教授的dropbox

代码如下:

#! /bin/bash
echo "Submit Lab$1? \c"

read choice

if [ $choice = "y" ]; then
   echo "Sending to Prof's dropbox..."
   cp -r /path/to/lab$1 /path/to/dropbox
else
   echo "Submission terminated."
fi
该命令的用法仅为“
$submit 1
”(1是一个整数,对应于我要提交的实验室)

bash脚本将输入的参数(一个整数)附加到必要的文件名(一个目录)中,然后使用
cp
将该目录提交给我的教授的dropbox

与其说是绝对必要的,不如说是为了学习,我想创建一个干净的提示符来捕获任何
cp
错误(例如文件不存在),并能够输出我自己的错误消息

所以基本上是这样的:

echo "Submit lab$1?"

read choice

echo "Send to Prof's dropbox"
cp -rv /path/to/lab$1 /path/to/dropbox

<catch any errors from cp>

if [ cp has errors ]

   echo "Submission failed."

else if [ cp has no errors ]

   echo "Submission successful."

And so on...
echo“提交实验室$1?”
阅读选择
echo“发送到教授的dropbox”
cp-rv/path/to/lab$1/path/to/dropbox
如果[cp有错误]
echo“提交失败”
否则,如果[cp没有错误]
echo“提交成功”
等等
我知道我可以使用verbose模式,而且
cp
本身会打印错误,但正如前面所述,我这样做是为了学习bash中的错误捕获,并能够做出清晰的提示

任何帮助都将不胜感激

谢谢


另外:我有一个类似的脚本,它使用
scp
从我的笔记本电脑提交实验室。假设我回答了这个问题,我可以用完全相同的方式将解决方案应用于scp吗

编辑:我不希望
cp
错误输出到shell!最常见的错误可能是“Cannotstatblah:没有这样的文件或目录”。我想抓住这个错误,简单地说“提交失败”

EDIT#2:jcollado的答案是正确的,问题在我这方面。未使用正确的“
fi
”结束嵌套的
if-else

修好后,它按预期工作。仍然需要捕获错误输出,但我相信我知道我需要自己去哪里解决这个问题,所以就我而言,这个问题已经得到了回答


最终编辑:啊,见鬼,重定向太简单了,我想我应该把解决方案放在这里。如果使用Linux,只需在
cp
之后添加“
2>/dev/null
”(如果您不想在任何文件中保存错误消息),即可使“
cp-r/first/path/second/path 2>/dev/null

检查上一个命令的返回代码,您可以使用特殊变量,如下所示:

if [ "$?" -ne "0" ]; then
  echo "Submission failed"
  exit 1
fi

echo "Submission successful."
此外,如果您想要一个干净的提示,您可以按说明重拨
stderr

最后,您还可以在使用
scp
的脚本中使用它,因为无论您使用的命令是什么,它都可以工作

echo "Submit lab$1?"

read choice

echo "Send to Prof's dropbox"
cp -rv /path/to/lab$1 /path/to/dropbox &>/dev/null

[ $? -eq 0 ] && { #success, do something } || { #fail, do something }

依此类推……

尽管可以测试$?,但也可以直接测试命令的退出状态:

if cp -rv /path/to/lab$1 /path/to/dropbox
then echo Submission successful
fi
exit $?
cp
已将错误报告为标准错误。如果
cp
成功,则显示的
exit
将以状态0(成功)退出;否则,它将以
cp
退出的状态退出


显然,如果愿意,您可以将其包装在循环中,也可以将其设置为非交互式(但任何退出都会终止脚本)。

感谢您的提示(无双关语)响应!我将进一步研究stderr重定向,因为这似乎是“干净提示”解决方案的所在。但是,您提供的代码不适用于失败的提交。当cp失败时,它不会打印“提交失败”。但是,当cp失败时,它忽略了“提交成功”。我注意到,当cp失败时,它执行后什么都没有。啊,问题出在我这方面。现在明白了。谢谢如果您不介意我问,“exit”之后的整数是做什么的?
exit
的参数是您自己脚本的结果代码。很好的做法是确保成功时退出代码为0,否则为非零,以便更高级别的脚本可以调用您的脚本并使用其结果代码来处理任何错误。感谢您提供的替代解决方案。基于简单性的最佳答案。我相信上面的退出代码永远是零。如果
cp
失败(返回非0),则
If
将返回0。bash的
echo
始终返回0。从手册页,关于
如果
:退出状态是最后执行的命令的退出状态,如果没有条件测试为真,则为零。@mr.spuratic:看起来您是正确的。如果为真,则运行
;然后回音为真;fi;echo$?
在Bash、Korn shell、Herigloom shell中打印true,然后打印0;如果为false,则替换为
;然后回音为真;fi;echo$?
只打印0。因此,
$?
状态不会保留在
if
中执行的命令的退出状态。围绕这一点,有多种方式,有大有小。其中之一是
status=0;如果是真的;然后回音为真;else状态=1;fi;echo$status
。或者您可以做相反的操作:
status=1;如果是真的;然后回音为真;状态=0;fi;echo$status
。可以(
bash
)使用
PIPESTATUS
:而不是由
if
的退出状态设置,如果条件为false,则从条件的命令列表中设置,否则在条件块内设置为正常。这适用于复合命令
if
while
直到
,以及(毫不奇怪地)
{}
。但我不清楚这是否是一种明确记录的行为。在这种情况下,我通常只将
$?
缓存在临时或本地ASAP中。