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 行。
可选择将 stdout
和 stderr
保存到文件中。
工作方式为 #!/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
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 行。
可选择将 stdout
和 stderr
保存到文件中。
工作方式为 #!/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