命令输出明明有换行,为什么存进 Shell 变量后不见了?
【摘要】 Bash 的 $(...) 会执行括号里的命令,再把标准输出作为替换结果。不过,它会移除输出末尾的所有换行符;输出中间的换行则会保留。这在读取配置或一行命令结果时很方便,但如果需要逐字节保存文件内容,就容易让人误以为数据没有变化。 看一个最小例子value=$(printf 'hello\n\n')printf '<%s>\n' "$value"输出是 <hello>:原本末尾的两个换行都没...
Bash 的 $(...) 会执行括号里的命令,再把标准输出作为替换结果。不过,它会移除输出末尾的所有换行符;输出中间的换行则会保留。
这在读取配置或一行命令结果时很方便,但如果需要逐字节保存文件内容,就容易让人误以为数据没有变化。
看一个最小例子
value=$(printf 'hello\n\n')
printf '<%s>\n' "$value"
输出是 <hello>:原本末尾的两个换行都没有进入变量。printf 最后加上的换行只是为了让演示结果单独占一行。
中间的换行仍然保留:
value=$(printf 'first\nsecond\n\n')
printf '<%s>\n' "$value"
这次尖括号之间有两行:first 和 second。两行之间的换行存在,second 后面原有的两个换行被移除了。
引号解决的是另一个问题
引用变量时,示例用了 "$value"。引号让变量内容作为一个参数传给 printf,避免其中的空格和换行在展开时被拆分;它不能把命令替换时已经移除的末尾换行找回来。
输出变量内容时,printf '%s' "$value" 比 echo "$value" 更适合精确控制格式,因为是否换行由格式字符串明确决定。
如果必须保留文件的原始字节
不要把文件内容先放进命令替换再写回。直接复制文件,或者通过管道传递数据:
cp source.txt copy.txt
cmp -s source.txt copy.txt && printf '内容一致\n'
这里的 cmp -s 静默比较文件内容;相同时返回成功状态,后面的提示才会执行。需要处理的数据流也可以交给支持标准输入的程序,而不是先装进变量。
除了末尾换行,Bash 变量也不能保存 NUL 字节。因此,包含任意二进制内容时,更适合用文件或管道传递。
我用临时文件验证了这些示例:两个尾随换行会被命令替换移除,中间换行保留;直接复制后,cmp 能确认包含尾随换行和 NUL 字节的文件内容一致。
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)