我有一个功能,旨在捕获命令的输出并缩进每一行:
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函数中,每行输出都将缩进。除了在read -p
内调用some command
之外,这种情况有效,例如:
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
$
提示不会显示并挂起等待输入。
在暂停输入之前有没有办法让提示显示?
答案 0 :(得分:3)
输入端的while read
循环(与许多其他工具一样)一次处理一行。由于提示不是在最后打印换行符,因此循环不会处理它。
在较高的层面上,您有两种选择:
由于get_name
函数无法修改,因此它是规范的一部分,我们最终在这里做的是修改shell环境以改变{{1工作。
read
将其提示写入stderr。
如果要重定向提示,请重定向FD 2.
如果你想确保其他重定向(例如read -p
,这会导致提示转到stdout - 正在被捕获)不适用,那么直接指向TTY :
2>&1
现在,如果您的目标是运行一个shell函数 - 您无法修改 - 一般情况下stderr被重定向但read -p "enter something" 2>/dev/tty
打印提示直接提示给TTY,可以< / em>完成,黑客攻击类似于以下内容:
read -p
...这样的:
reading_to_tty() {
read() { builtin read "$@" 2>/dev/tty; }
"$@"
unset -f read
}
...将运行reading_to_tty get_name 2>&1
,使用get_name
命令(而不是其他命令)将stderr内容直接发送到TTY。
根据扩展讨论,确保将提示刷新到管道格式化的另一种方法是附加换行符。下面这样做,因此可以使用通过格式化功能的现有管道:
read
...以与上述相同的方式使用:
reading_with_prompt_newline() {
read() {
if [[ $1 = -p ]]; then
set -- "$1" "$2"$'\n' "${@:3}"
fi
builtin read "$@"
}
"$@"
unset -f read
}