我有一个函数,旨在捕获命令的输出并缩进每一行:
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
}
Run Code Online (Sandbox Code Playgroud)
这是这样使用的:
some command 2>&1 | indent_lines
Run Code Online (Sandbox Code Playgroud)
来自的整个输出通过some command 2>&1
管道传输到 indent_lines 函数中,并且每一行输出都将缩进。这适用于read -p
in 从 inside 调用的情况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"
}
Run Code Online (Sandbox Code Playgroud)
输出是:
$ 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
$
Run Code Online (Sandbox Code Playgroud)
不显示提示并挂起等待输入。
有没有办法在暂停输入之前让提示显示?
while read
输入端的循环(像许多其他工具一样)一次处理一行。由于提示最后没有打印换行符,因此它不会由循环处理。
概括地说,您有两种选择:
由于get_name
函数不能被修改是规范的一部分,我们最终要做的是修改 shell 环境以改变read
工作方式。
read -p
将其提示写入 stderr。
如果要重定向提示,则重定向 FD 2。
如果您想确保其他重定向(例如 a 2>&1
,这会导致提示转到标准输出 - 正在被捕获)不适用,则直接指向 TTY:
read -p "enter something" 2>/dev/tty
Run Code Online (Sandbox Code Playgroud)
现在,如果你的目标是运行一个 shell 函数——你不能修改它——一般read -p
会重定向 stderr 但将提示直接打印到 TTY,那么可以使用类似于以下内容的 hack:
reading_to_tty() {
read() { builtin read "$@" 2>/dev/tty; }
"$@"
unset -f read
}
Run Code Online (Sandbox Code Playgroud)
...因此:
reading_to_tty get_name 2>&1
Run Code Online (Sandbox Code Playgroud)
...将运行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
}
Run Code Online (Sandbox Code Playgroud)
...以与上述相同的方式使用:
reading_with_prompt_newline get_name
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1175 次 |
最近记录: |