Linux CLI 监视开关 -e, --errexit 意外退出与"command exit with a non-zero status, press a key to exit"



Linux CLIwatch命令有一个开关-e--errexit有一个描述:

在命令出错时冻结更新,并在按键后退出。

如果该开关返回非零退出代码,则应使监视停止执行命令。

问题是,如果命令的输出不适合 CLI 窗口,watch就会终止。 当 CLI 窗口在 Ubuntu 18.04 上全屏时,有时会出现问题,并且总是在您调整窗口大小或小于全屏时出现。

具有命令的脚本示例:

task.sh

#!/bin/sh
for i in $(seq 1 200)
do
printf "Task #${i}n";
done
exit 0;

和监视命令:

watch -e -n 1 ./task.sh;

观看意外错误:

命令以非零状态退出,按任意键退出

如何解决这个问题?我无法将标准输出重定向到/dev/null,因为至少需要打印使用watch执行的命令的部分输出,如果执行脚本的任何命令返回非零退出代码,手表应该终止,所以我想我被迫使用-e--errexit开关。

如果该特定watch行为没有好的解决方案,那么watch是否有任何好的替代品?

编辑

看起来watch问题与多个命令打印超过可见终端输出而不是打印字符串的总和有关。 此示例使用单个printf,在调整终端屏幕大小时没有任何问题,即使它打印的比终端的可见部分更多:

#!/bin/sh
output="";
for i in $(seq 1 200)
do
output="${output}$(printf "Task #${i}")n";
done
printf "$output";
exit 0;

但是这个技巧可以使用相对较小的脚本,我无法想象使用 watch 并为 srcipt 中的每个命令执行此解决方法 task.sh

另一种解决方法:

#!/usr/bin/env bash
temp="$(mktemp /tmp/watch.XXXXXXX)"
exec 3>&1;  exec > $temp
date # for demo purpose
for i in $(seq 1 200)
do
printf "Task #${i}n";
done
exec 1>&3
cat $temp; rm $temp

因此,您无需对原始 bash 脚本进行太多更改。

我想不出使用变量的方法,如果tmp文件真的是一个问题,请尝试以下操作:

#!/usr/bin/env bash
{
date # for demo purpose
for i in $(seq 1 200)
do
printf "Task #${i}n";
done
} | head -n $LINES

带有-e开关的watch的任务包装器(出错时退出(。
调整终端窗口大小时没有任何问题,即使只有 1 行。
可以选择将stdoutstderr保存到文件中。

可按#!/bin/bash#!/bin/sh
工作

task-wrapper.sh

#!/bin/sh
# path to file where to put stdout and stderr on error
error_log="$1";
output="$(
# exit sub shell with non zero code on 
# any line in sub shell having non zero exit code
set -e; 
{
# ========== Commands Block =============
# uncomment below to simulate an error
# ls /this/is/non/existing/path;
# an example of lot of print exceeding
# count of displayed terminal lines
for i in $(seq 1 200)
do
printf "Task #${i}n";
done
# uncomment below to simulate an error
# ls /this/is/non/existing/path;
# ========== Commands Block =============
} 2>&1;
)";
# get sub shell exit code
# print output (limit to terminal capacity)
# save error if any
# exit with error code if any
# or exit 0;
ec="$?"; if [ $ec -eq 0 ]; then 
# zero exit code
# prevent echo if there are only two
# lines of terminal available because
# they may be already consumed by watch
# and its status if watch run without 
# --no-title switch (default)
if [ $LINES -gt 2 ]; then
echo "$output" | tail -n "$(($LINES - 2))";
fi;
exit 0; 
else
# non zero exit code
# watch on error
# consumes additional one line
# therefore don't echo if lines
# available are less than 4
if [ "$LINES" -gt 3 ]; then 
echo "$output" | tail -n "$(($LINES - 3))";
fi;
# watch erases terminal
# output after press of any key 
# and its teminal print has no scroll
# so save whole stdout and stderr to file
# if path to it was provided
if [ -n "$error_log" ]; then
echo "$output" > "$error_log";
fi;
# exit with sub shell exit code
exit "$ec"; 
fi;

用法:

watch -e ./task-wrapper.sh

使用创建为错误日志的文件路径

watch -e ./task-wrapper.sh ./task-error.log

最新更新