首先,我不确定我是否正确地提出了问题。 所以我有一个删除系统中用户的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不应该显示在命令旁边或下面而不是它上面吗?
提前致谢
答案 0 :(得分:3)
当shell执行第echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName)"
行时,这是事件序列:
chsh -s /usr/bin/false Test2
,其stdout转到捕获缓冲区,以便shell稍后可以使用它。chsh
发现“Test2”不存在,并将“chsh:unknown user:Test2”打印到其stderr。由于shell没有对stderr做任何特殊处理,因此直接进入shell的stderr,这是你的终端。chsh
退出chsh
获取捕获的输出(注意:stdout,而不是stderr)(没有任何),并将其替换为echo
命令行,给出echo -e "Deactivating Test2 shell account ..." ""
请注意,错误消息会在步骤2中打印出来,但是在步骤4之前不会打印有关应该发生的消息。
有几种方法可以解决这个问题;通常最好的方法是避免捕获命令输出的整个混乱,然后回应它。这是毫无意义的,只会导致像这样的混乱(以及其他一些你没有碰到的东西)。只需直接运行命令,让其输出(stdout和stderr)按正常顺序进入正常位置。
顺便说一下,我还建议避免使用echo -e
或echo -anything
。 POSIX 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)"
通常,最好在尝试停用之前检查用户是否存在。