如何实现可重复调用的实时缩进Bash管道函数?
问题描述
需要实现一个满足以下要求的Bash函数:
- 可通过管道调用,如
echo input | my_function - 为每行输入添加开头缩进(制表符
\t) - 支持重复调用实现多级缩进,例如
echo input | my_function | my_function输出\t\tinput - 无需等待全部输入完成,可实时逐行输出
测试脚本如下:
#!/usr/bin/env bash main() { echo 'first:' echo 'once' | tab_indent_to_right echo 'twice' | tab_indent_to_right | tab_indent_to_right { echo 'wait 2 sec' sleep 2 echo 'wait 2 sec' sleep 2 echo 'waited' } | tab_indent_to_right } tab_indent_to_right() { # while read -r line; do echo $'\t'"$line"; done # 🔴 无法实现双重缩进 # awk -v prefix='\t' '{print prefix $0}' # 🔴 存在缓冲问题 # sed 's/^/\t/' # 🔴 存在缓冲问题 # xargs -I {} echo $'\t{}' # 🔴 无法实现双重缩进 # xargs -L1 echo $'\t' # 🔴 无法实现双重缩进 } main
现有尝试方案存在两类问题:
- 无法实现重复调用的多级缩进:部分写法在管道串联时无法累积缩进效果
- 存在输出缓冲:需等待所有输入生成完毕(如
sleep执行完成)才批量输出,无法实时逐行打印
解决方案
修改tab_indent_to_right函数为以下实现即可满足所有需求:
tab_indent_to_right() { while IFS= read -r line || [[ -n "$line" ]]; do printf '\t%s\n' "$line" done }
方案说明:
支持多级缩进:
每次调用函数都会为当前输入的每一行开头添加一个制表符,当通过管道串联调用时,前一次函数输出的已缩进内容会作为下一次函数的输入,自然累积生成多级缩进(两次调用就会添加两个\t)。实时逐行输出:
while read -r line会逐行读取输入流,每读取一行就立即处理并输出,不存在批量缓冲延迟;- 使用
printf替代echo,避免echo对特殊字符的潜在处理问题,同时保证输出格式的一致性; IFS= read -r line的写法可以保留输入行开头和结尾的空格,且避免read将反斜杠解析为转义字符;|| [[ -n "$line" ]]则能处理输入最后一行没有换行符的情况,确保所有内容都被正确处理。
运行修改后的测试脚本,即可看到符合预期的输出:
echo 'once' | tab_indent_to_right输出\tonceecho 'twice' | tab_indent_to_right | tab_indent_to_right输出\t\ttwice- 带
sleep的代码块会实时逐行输出:先打印\twait 2 sec,等待2秒后打印\twait 2 sec,再等待2秒后打印\twaited
内容的提问来源于stack exchange,提问作者U. Bulle
相关产品推荐
相关产品推荐

