bash无限循环内echo -n无法即时输出?原因及解法咨询
问题描述
需要编写一段Bash无限循环脚本,实现两个功能:
- 读取用户输入
- 去除输入中的多余空格后,无换行输出
原始脚本(无法正常工作)
#!/bin/bash -u # Does not work. while :; do read -p "Type, and press ENTER: " echo -n "$REPLY" done | sed -u -E 's/ +//g'
运行后始终看不到输出,只能用Ctrl-C退出:
$ ./script.sh Type, and press ENTER: a b c Type, and press ENTER: d e f Type, and press ENTER: g h i Type, and press ENTER: ^C
去掉echo -n后的脚本(可输出但不符合需求)
去掉echo的-n参数后,脚本能正常通过sed输出结果,但会换行,不符合无换行的需求:
# This works. while :; do read -p "Type, and press ENTER: " echo "$REPLY" # <--------------- -n removed done | sed -u -E 's/ +//g'
临时解决方案(可正常实现功能)
将sed移到循环内部后,脚本可以正常实现功能:
# Workaround, that works! while :; do read -p "Type, and press ENTER: " echo "$REPLY" | sed -u -E 's/ +//g' done
运行结果:
$ ./script.sh Type, and press ENTER: a b c abc Type, and press ENTER: d e f def Type, and press ENTER: ^C
疑问:为何原始脚本无法正常工作,而临时解决方案却可以?
原因分析
原始脚本失效的核心原因
虽然脚本给sed加了-u参数开启无缓冲输出,但sed本质是行驱动工具——它默认要等输入中出现换行符,才会把当前攒的内容当作一行来处理并输出。
原始脚本里用echo -n "$REPLY"输出的内容不带换行,每一次用户输入的内容都会被拼进同一段无换行的数据流里。哪怕sed关闭了缓冲,它也一直在等换行符触发处理逻辑,所以永远看不到输出,直到脚本被终止。
补充:管道会让while循环在子shell中执行,但这不是无输出的直接原因,核心还是sed的行处理特性遇上了无换行输入。
临时方案有效的原因
把sed挪到循环内部后,每次echo "$REPLY"都会输出带换行符的完整一行。sed收到换行符后,立刻就能识别这是一行完整输入,执行空格替换后输出结果(这里sed会保留原有的换行,所以每次输入后都会输出一行处理后的内容)。
哪怕开启了-u,此时因为每段输入都有换行收尾,sed能正常触发处理逻辑,所以输出是实时的。
额外优化:无需外部工具的实现方式
如果想实现无换行输出,其实不需要依赖sed,直接用Bash的参数替换就能搞定,还没有缓冲问题:
#!/bin/bash -u while :; do read -p "Type, and press ENTER: " echo -n "${REPLY// /}" done
${REPLY// /}的作用是把$REPLY里的所有空格替换为空,直接输出处理后的内容,完全符合需求。
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

