Bash 脚本标准错误和标准输出
Bash script stderr and stdout
首先,我不确定我是否正确地提出了问题。
所以我有一个 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,即本例"supposedly"不存在(不同时间不同题)。现在,stderr 消息不应该显示在命令旁边或命令下方而不是命令上方吗?
提前致谢
Now, shouldn't the stderr msg display next to the command or below it instead of above it?
不,因为先执行命令然后然后回显其输出。在两个单独的行中执行 echo 和命令。
那是因为 chsh 在 bash 有机会写入 stdout 之前写入 stderr。将 stderr 重定向到 stdout 以使其正确:
echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName 2>&1)"
一般来说,最好先检查用户是否存在,然后再尝试停用它。
当 shell 执行行 echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName)"
时,事件顺序如下:
- shell运行s
chsh -s /usr/bin/false Test2
,其标准输出进入捕获缓冲区,以便 shell 稍后可以使用它。
chsh
发现 "Test2" 不存在,并将 "chsh: unknown user: Test2" 打印到它的标准错误。因为 shell 没有对它的 stderr 做任何特殊的事情,这直接进入 shell 的 stderr,这是你的终端。
chsh
退出
- shell 从
chsh
(没有任何输出)获取捕获的输出(注意:stdout,不是 stderr),并将其替换到 echo
命令行中,给予 echo -e "Deactivating Test2 shell account ..." ""
请注意,错误消息是在第 2 步打印出来的,但是关于应该发生的事情的消息直到第 4 步才会打印出来。
有几种方法可以解决这个问题;一般来说,最好的办法是避免捕获命令输出的整个混乱,然后回显它。这是毫无意义的,只会导致像这样的混乱(以及其他一些你没有 运行 的)。直接 运行 命令,让它的输出(stdout 和 stderr)按正常顺序到达它们的正常位置。
顺便说一句,我还建议避免使用 echo -e
,甚至 echo -anything
。 POSIX standard for echo
表示 "Implementations shall not support any options." 实际上,一些实现确实支持选项;其他人只是将它们视为要打印的字符串的一部分。此外,一些解释要打印的字符串中的转义序列(如 \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"
首先,我不确定我是否正确地提出了问题。 所以我有一个 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,即本例"supposedly"不存在(不同时间不同题)。现在,stderr 消息不应该显示在命令旁边或命令下方而不是命令上方吗?
提前致谢
Now, shouldn't the stderr msg display next to the command or below it instead of above it?
不,因为先执行命令然后然后回显其输出。在两个单独的行中执行 echo 和命令。
那是因为 chsh 在 bash 有机会写入 stdout 之前写入 stderr。将 stderr 重定向到 stdout 以使其正确:
echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName 2>&1)"
一般来说,最好先检查用户是否存在,然后再尝试停用它。
当 shell 执行行 echo -e "Deactivating $UserName shell account ..." "$(chsh -s /usr/bin/false $UserName)"
时,事件顺序如下:
- shell运行s
chsh -s /usr/bin/false Test2
,其标准输出进入捕获缓冲区,以便 shell 稍后可以使用它。 chsh
发现 "Test2" 不存在,并将 "chsh: unknown user: Test2" 打印到它的标准错误。因为 shell 没有对它的 stderr 做任何特殊的事情,这直接进入 shell 的 stderr,这是你的终端。chsh
退出- shell 从
chsh
(没有任何输出)获取捕获的输出(注意:stdout,不是 stderr),并将其替换到echo
命令行中,给予echo -e "Deactivating Test2 shell account ..." ""
请注意,错误消息是在第 2 步打印出来的,但是关于应该发生的事情的消息直到第 4 步才会打印出来。
有几种方法可以解决这个问题;一般来说,最好的办法是避免捕获命令输出的整个混乱,然后回显它。这是毫无意义的,只会导致像这样的混乱(以及其他一些你没有 运行 的)。直接 运行 命令,让它的输出(stdout 和 stderr)按正常顺序到达它们的正常位置。
顺便说一句,我还建议避免使用 echo -e
,甚至 echo -anything
。 POSIX standard for echo
表示 "Implementations shall not support any options." 实际上,一些实现确实支持选项;其他人只是将它们视为要打印的字符串的一部分。此外,一些解释要打印的字符串中的转义序列(如 \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"