Linux CLI watch switch -e, --errexit unexpected exit with "command exit with a non-zero status, press a key to exit"

Linux CLI watch switch -e, --errexit unexpected exit with "command exit with a non-zero status, press a key to exit"

Linux CLI watch 命令有开关 -e, --errexit 有一个描述:

Freeze updates on command error, and exit after a key press.

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

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

具有命令的脚本示例:

task.sh

#!/bin/sh

for i in $(seq 1 200)
do
    printf "Task #${i}\n";
done

exit 0;

并观看命令:

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

观看意外错误:

command exit with a non-zero status, press a key to exit

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

如果没有针对特定 watch 行为的好的解决方案,是否有替代 watch 的好的方法?

编辑

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

#!/bin/sh

output="";
for i in $(seq 1 200)
do
    output="${output}$(printf "Task #${i}")\n";
done

printf "$output";
exit 0;

但是这个 hack 可以使用相对较小的脚本,我无法想象使用 watch 并对 task.sh srcipt

中的每个命令执行此解决方法

另一种解决方法:

#!/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 的任务包装器(出错时退出)。
调整终端 window 大小时没有任何问题,甚至只有 1 行。
可选择将 stdoutstderr 保存到文件中。

工作方式为 #!/bin/bash#!/bin/sh

任务-wrapper.sh

#!/bin/sh

# path to file where to put stdout and stderr on error
error_log="";

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