bash - 从脚本中通过管道传输 stdout/stderr 时不显示 read -p 提示

标签 bash shell

我有一个函数旨在捕获命令的输出并缩进每一行:

indent_lines () {
  local line
  local indent="        "

  while IFS= read -r line || [[ -n "$line" ]]; do
      # remove \r and replace with \r$indent
      echo "$indent $(echo "$line" | sed "s/$(printf '\r')/$(printf '\r')$indent /g")"
  done
}

它是这样使用的:

some command 2>&1 | indent_lines

some command 2>&1 的整个输出被输送到 indent_lines 函数中,每一行输出都将被缩进。这适用于从 some command 中调用 read -p 的情况,例如:

get_name () {
   echo "this is a line of output 1"
   echo "this is a line of output 2"
   echo "this is a line of output 3"
   read -p "enter your name: " user_input
   echo
   echo "$user_input is your name"
}

输出是:

$ get_name 2>&1 | indent_lines
$        this is a line of output 1
$        this is a line of output 2
$        this is a line of output 3
$

提示不显示,挂起等待输入。

有什么办法可以让输入暂停前显示提示?

最佳答案

输入端的 while read 循环(与许多其他工具一样)一次处理一行。由于提示未在末尾打印换行符,因此它不会由循环处理。

在高层次上,您有两个选择:

  • 避开提示的管道
  • 添加换行符以便刷新内容

由于 get_name 函数不能被修改是规范的一部分,我们最终要做的是修改 shell 环境以改变 read 的方式有效。


避开管道

read -p 将其提示写入 stderr。

如果要重定向提示,则重定向 FD 2。

如果你想确保其他重定向(例如 2>&1,这会导致提示转到 stdout -- 正在被捕获)不适用,那么直接到TTY 明确:

read -p "enter something" 2>/dev/tty

添加换行符

现在,如果您的目标是运行一个 shell 函数——您不能修改它——通常重定向 stderr,但 read -p 打印提示直接到 TTY,可以通过类似于以下的 hack 来完成:

reading_to_tty() {
  read() { builtin read "$@" 2>/dev/tty; }
  "$@"
  unset -f read
}

...因此:

reading_to_tty get_name 2>&1

...将运行 get_name,使用 read 命令(而不是其他命令)将 stderr 内容直接发送到 TTY。


根据扩展讨论,确保将提示刷新到管道格式的另一种方法是附加换行符。下面是这样做的,因此可以使用通过格式化函数的现有管道:

reading_with_prompt_newline() { 
  read() {
    if [[ $1 = -p ]]; then 
      set -- "$1" "$2"$'\n' "${@:3}" 
    fi 
    builtin read "$@" 
  } 
  "$@" 
  unset -f read 
}

...使用方法同上:

reading_with_prompt_newline get_name 

关于bash - 从脚本中通过管道传输 stdout/stderr 时不显示 read -p 提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37445717/

相关文章:

bash - 是否有包含剪贴板内容的环境变量?

regex - 根据第二个文本文件从文本文件中删除重复项

shell - openshift 命令以编程方式/脚本捕获 POD 名称

当我重定向输出时,Python 程序不会在 docker 容器中的 shell 脚本中运行

linux - 无法在 shell 脚本中打印公共(public) ip

linux - Shell脚本变量结构

linux - 如何创建与一天中的分钟相对应的文件?

shell - 使用 shell 脚本从两个目录中查找和移动重复文件

linux - 在 Linux 中重新启动文件更改进程

python - BASH - crontab 始终运行,除了 python 脚本