AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / computer / 问题 / 1827225
Accepted
Zsar
Zsar
Asked: 2024-01-25 00:38:54 +0800 CST2024-01-25 00:38:54 +0800 CST 2024-01-25 00:38:54 +0800 CST

如何使bash脚本输出与终端和文件兼容?

  • 772

在 bash 中,如果我想生成定期状态消息,我可以通过发出热键组合来替换前一个状态消息,例如,如此处、此处或此处所示。当用户直接执行脚本时,这很好,因为它可以让他们随时了解情况,而不会弄乱屏幕。

但是,如果他们想在自动化上下文中使用相同的脚本,则输出将(必须)重定向到文件中:

./test.sh >log.txt

此时,\r、 、\b都\033[0K不起作用。

我如何使其适用于两种模式?

(例如,如果我可以检测输出流是否是文件,那么省略中间消息就足够简单了。)

  • 如果可能的话,我想避免在脚本中引入参数。现实世界的版本已经附带了几个。
  • 如果可能的话,我想避免处理脚本本身内部的输出流,例如根据这个问题,因此当嵌入到其他脚本中时它不会表现出令人惊讶的行为。

示例代码test.sh:

#!/bin/bash

PREVIOUS_JOB_STATUS=""
SECONDS=0          # auto-incremented by Bash; divide by INTERVAL_SECONDS to get number of retries
INTERVAL_SECONDS=3 # interval between polls to the server
TIMEOUT_SECONDS=10 # how long until we give up, because the server is clearly busy (or dead)
while true; do
  RETRY_SECONDS=$SECONDS
  if [ $RETRY_SECONDS -lt $INTERVAL_SECONDS ]; then # in the real world, here would be      the polling operation
    JOB_STATUS='queued'
  else
    JOB_STATUS='processing'
  fi
  RESULT=1                                          # in the real world, here would be ? of the polling operation
  if [ $RESULT -eq 0 ]; then                            # success
    exit $RESULT
  elif [ $RETRY_SECONDS -gt $TIMEOUT_SECONDS ]; then    # failure (or at least surrender)
    echo "Timeout exceeded waiting for job to finish. Current Job Status is '$JOB_STATUS'. Current result code is '$RESULT'."
    exit $RESULT
  elif [ "$PREVIOUS_JOB_STATUS" = "$JOB_STATUS" ]; then # no change yet,      replace last status message and try again
    echo -en '\033[1A\r\033[K' # move one line up                                : \033[1A ,
                               # move to pos1                                    : \r      ,
                               # delete everything between cursor and end-of-line: \033[K  ,
                               # omit line break                                 : -n
  else                                                  # job status changed, write   new  status message and try again
    PREVIOUS_JOB_STATUS=$JOB_STATUS
  fi
  SLEEP_MESSAGE='Waiting for job to finish. Waited '`printf "%02g" $SECONDS`" s. Current job status is '$JOB_STATUS'. Current result code is '$RESULT'."
  echo $SLEEP_MESSAGE
  sleep $INTERVAL_SECONDS
done

最终输出./test.sh:

Waiting for job to finish. Waited 00 s. Current job status is 'queued'. Current result code is '1'.
Waiting for job to finish. Waited 09 s. Current job status is 'processing'. Current result code is '1'.
Timeout exceeded waiting for job to finish. Current Job Status is 'processing'. Current result code is '1'.

最终输出./test.sh >log.txt 2>&1:

Waiting for job to finish. Waited 00 s. Current job status is 'queued'. Current result code is '1'.
Waiting for job to finish. Waited 03 s. Current job status is 'processing'. Current result code is '1'.
^[[1A^M^[[KWaiting for job to finish. Waited 06 s. Current job status is 'processing'. Current result code is '1'.
^[[1A^M^[[KWaiting for job to finish. Waited 09 s. Current job status is 'processing'. Current result code is '1'.
Timeout exceeded waiting for job to finish. Current Job Status is 'processing'. Current result code is '1'.

期望的最终输出./test.sh >log.txt 2>&1: 等于 的最终输出./test.sh。

linux
  • 1 1 个回答
  • 29 Views

1 个回答

  • Voted
  1. Best Answer
    Kamil Maciorowski
    2024-01-25T01:01:35+08:002024-01-25T01:01:35+08:00

    使用test -t 1或test -t 2分别测试 stdout 或 stderr 是否与终端关联。

    -t file_descriptor
    如果文件描述符号 file_descriptor 已打开并且与终端关联,则为 True。如果file_descriptor不是有效的文件描述符编号,或者文件描述符编号file_descriptor未打开,或者已打开但未与终端关联,则为 False。

    (来源)

    概念证明:

    sh -c '
    test -t 1 && echo foo 
    echo bar
    '
    

    按原样运行上面的代码,您将看到foo和bar。将输出重定向到远离终端的位置(例如重定向到常规文件,或通过管道传输到cat)并且foo不会被打印。

    为了避免每次需要打印中间消息时进行测试,请使用以下技巧:

    if test -t 1; then exec 5>&1; else exec 5>/dev/null; fi
    

    现在将每条中间消息打印到文件描述符 5 (例如echo baz >&5)。如果它是终端,它将转到标准输出,/dev/null否则。

    • 2

相关问题

  • 如何让我的 Linux 机器看起来像是在运行 Windows?

  • 对于 cp 或 mv,是否有等同于 cd - 的东西?

  • 以 root 身份运行 docker 容器

  • 如何在域和 Linux 活动目录中启用指纹传感器

  • 如何在CentOS 7 中将Ctrl+C 永久更改为Ctrl+K?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何减少“vmmem”进程的消耗?

    • 11 个回答
  • Marko Smith

    从 Microsoft Stream 下载视频

    • 4 个回答
  • Marko Smith

    Google Chrome DevTools 无法解析 SourceMap:chrome-extension

    • 6 个回答
  • Marko Smith

    Windows 照片查看器因为内存不足而无法运行?

    • 5 个回答
  • Marko Smith

    支持结束后如何激活 WindowsXP?

    • 6 个回答
  • Marko Smith

    远程桌面间歇性冻结

    • 7 个回答
  • Marko Smith

    子网掩码 /32 是什么意思?

    • 6 个回答
  • Marko Smith

    鼠标指针在 Windows 中按下的箭头键上移动?

    • 1 个回答
  • Marko Smith

    VirtualBox 无法以 VERR_NEM_VM_CREATE_FAILED 启动

    • 8 个回答
  • Marko Smith

    应用程序不会出现在 MacBook 的摄像头和麦克风隐私设置中

    • 5 个回答
  • Martin Hope
    Vickel Firefox 不再允许粘贴到 WhatsApp 网页中? 2023-08-18 05:04:35 +0800 CST
  • Martin Hope
    Saaru Lindestøkke 为什么使用 Python 的 tar 库时 tar.xz 文件比 macOS tar 小 15 倍? 2021-03-14 09:37:48 +0800 CST
  • Martin Hope
    CiaranWelsh 如何减少“vmmem”进程的消耗? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Windows 10 搜索未加载,显示空白窗口 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    andre_ss6 远程桌面间歇性冻结 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney 为什么在 URL 后面加一个点会删除登录信息? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension 鼠标指针在 Windows 中按下的箭头键上移动? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca 我所有的 Firefox 附加组件突然被禁用了,我该如何重新启用它们? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK 是否可以使用文本创建二维码? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 更改 git init 默认分支名称 2019-04-01 06:16:56 +0800 CST

热门标签

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve