我有一个函数旨在捕获命令的输出并缩进每一行:
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/