Bash脚本stderr和stdout

时间:2016-12-26 02:03:50

标签: bash stdout stderr

首先,我不确定我是否正确地提出了问题。 所以我有一个删除系统中用户的bash脚本。问题是,它显示终端代码之前的错误消息。 这里。 代码:

echo -e "\nCommencing user $UserName removal"
echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName)"
echo -e "Listing group(s) user: " "$(groups $UserName)"
echo -e "Removing Crontab ... " "$(crontab -r -u $UserName)"

这是输出:

Commencing user Test2 removal
chsh: unknown user: Test2
Deactivating Test2 shell account ...
groups: Test2: no such user
Listing group(s) user:  
scripts/sudo.sh: line 332: /delete_Test2/crontab.bak: No such file or directory
Saving Crontab ...  

要删除的用户是Test2,这种情况“据说”不存在(不同时间的不同问题)。现在,stderr msg不应该显示在命令旁边或下面而不是它上面吗?

提前致谢

3 个答案:

答案 0 :(得分:3)

当shell执行第echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName)"行时,这是事件序列:

  1. shell运行chsh -s /usr/bin/false Test2,其stdout转到捕获缓冲区,以便shell稍后可以使用它。
  2. chsh发现“Test2”不存在,并将“chsh:unknown user:Test2”打印到其stderr。由于shell没有对stderr做任何特殊处理,因此直接进入shell的stderr,这是你的终端。
  3. chsh退出
  4. shell从chsh获取捕获的输出(注意:stdout,而不是stderr)(没有任何),并将其替换为echo命令行,给出echo -e "Deactivating Test2 shell account ..." ""
  5. 请注意,错误消息会在步骤2中打印出来,但是在步骤4之前不会打印有关应该发生的消息。

    有几种方法可以解决这个问题;通常最好的方法是避免捕获命令输出的整个混乱,然后回应它。这是毫无意义的,只会导致像这样的混乱(以及其他一些你没有碰到的东西)。只需直接运行命令,让其输出(stdout和stderr)按正常顺序进入正常位置。

    顺便说一下,我还建议避免使用echo -eecho -anythingPOSIX standard for echo表示“实施不支持任何选项”。实际上,一些实现确实支持选项;其他人只是将它们视为要打印的字符串的一部分。此外,有些解释要打印的字符串中的转义序列(如\n),有些则不解释,有些仅在指定-e时才会解释(违反POSIX标准)。鉴于这些功能有多么难以预测,最好只是避免这种不确定的情况,而是使用printf代替(使用起来更复杂,但更可预测),或者(如你的情况)只使用一个单独的每行echo命令。

    此外,您应该几乎总是双引号变量引用(例如groups "$UserName"而不是groups $UserName),以防它们包含空格,通配符等。

    基于以上所述,这是我编写脚本的方式:

    echo    # print a blank line
    echo "Commencing user $UserName removal"
    echo "Deactivating $UserName shell account ..."
    chsh -s /usr/bin/false "$UserName"
    
    echo "Listing group(s) user: "
    groups "$UserName"
    
    echo "Removing Crontab ... "
    crontab -r -u "$UserName"
    

答案 1 :(得分:1)

  

现在,stderr msg不应该显示在命令旁边或下面而不是它上面吗?

不,因为首先执行命令而然后它的输出被回显。在两个单独的行中执行echo和命令。

答案 2 :(得分:1)

那是因为在 bash有机会写入stdout之前,chsh正在写入stderr 。将stderr重定向到stdout以使其正确:

echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName 2>&1)"

通常,最好在尝试停用之前检查用户是否存在。