当前位置: 代码网 > 服务器>服务器>Linux > 从入门到精通详解Linux中printf命令用法的完全指南

从入门到精通详解Linux中printf命令用法的完全指南

2026年09月17日 Linux 我要评论
如果你刚接触 linux,第一次在命令行敲 printf --help ,大概率会产生一个很自然的疑问:“printf 不是 c 语言的函数吗?怎么命令行里也有一个?”&m

如果你刚接触 linux,第一次在命令行敲 printf --help ,大概率会产生一个很自然的疑问:“printf 不是 c 语言的函数吗?怎么命令行里也有一个?”——不用慌,你没穿越。linux 里的 printf 是 shell 自带(bash 内建)的格式化输出命令,它和 c 语言的 printf 函数算得上同宗同源,都继承自 c 标准库的设计思路,只是从“编程语言的输出函数”变成了“命令行里的文本排版工具”。我见过太多人写脚本时只会用 echo ,等到需要输出带小数点的统计结果、要对齐几列数据、要在日志里拼时间戳时,才开始手忙脚乱地拼字符串、数空格,拼到眼冒金星。其实你用 printf ,好些问题直接就解决了。

这篇我打算把 printf 命令从语法、格式符、转义字符,到实际场景里的表格对齐、重定向、颜色输出,再到中文乱码、浮点精度、编译警告这些坑,一次性讲透。文章面向所有想在 linux 命令行和 shell 脚本里把输出做得干净、规范的人——不管你是刚在虚拟机里装好系统的新手,还是天天跟内核、嵌入式打交道的老手, printf 命令都值得你花二十分钟彻底搞明白。

1. 先搞清楚:printf 命令到底是什么

1.1 命令行里的 printf 和 c 语言的 printf,有什么关系

很多初学者第一次在终端里输入 printf "hello" 时会愣一下,因为它输出结果居然不带换行,光标直接停在 hello 后面,下一行提示符紧贴着冒出来,看起来像“卡住了”。这就是第一个需要记住的知识点: printf 命令默认不会自动换行 ,它只是把你给的格式字符串按规则翻译成文本,然后原样输出到标准输出(stdout)。要不要换行,由你自己在格式字符串里写 \n 决定。

那它跟 c 语言的 printf 函数是什么关系?简单说: bash printf 命令是 c 语言 printf 函数的一个“命令行克隆版”,格式说明符( %s %d %f 这些)和转义字符( \n \t 这些)的设计几乎一一对应,所以写过 c 的人上手极快。但两者不是同一个东西:c 语言的 printf 是函数,需要 #include <stdio.h> 并且有返回值;bash 里的 printf 是内建命令,直接面向终端做文本输出。唯一容易让人混淆的场景是“c 语言程序里的 printf”,那就是调用标准库函数了,跟这里的命令是两回事。

我建议你把 shell 里的 printf 理解为“带格式的 echo”。 echo 是个没心没肺的复读机,你给它什么它就原样吐什么;而 printf 是个严谨的排版师傅,它会先看你给的“模板”长什么样,再把后面的参数一个个填进模板的槽位里,最后把填好的整段文本交出去。这个“模板 + 参数”的模型,就是 printf 最核心的东西。

1.2 为什么有了 echo,还必须学 printf

理论上,echo 确实能搞定 80% 的简单输出。但一旦涉及这几种情况,echo 就会让你很难受:

  • 输出固定宽度的数字(比如把所有进程的 pid 都按 5 位对齐);
  • 输出带小数位的百分比(比如“使用率 73.45%”);
  • 把数据排成规整的表格,列和列之间严格对齐;
  • 给输出加颜色、加 ansi 转义序列。

这些需求用 echo 写,基本就是硬拼空格、硬拼字符串,脚本越长,对不齐的概率越大。而 printf 的格式说明符天生就是干这个的,你只需要告诉它“这一列占 10 个字符宽度,不够就补空格,内容左对齐还是右对齐”,它就会老老实实执行,不管你的数据是 1 还是 1234567890。

再补充一个实操背景: printf 不只存在于 bash 里, zsh ksh dash 也都有内建的 printf ;就算在一些没有内建支持的极简 shell 环境里,系统通常也会提供 /usr/bin/printf 这个外部命令。换句话说, printf 是跨 shell 环境的标准能力 ,学一次到处都能用。这也是为什么尽管 echo 看起来更简单,我还是强烈建议你把 printf 当成日常脚本的主力输出工具。

2. 语法核心:格式字符串与格式说明符

2.1 基本格式:printf format [argument]...

先看最基础的调用形式:

printf format [argument]...
  • format 是格式字符串,它描述了你想要什么样的输出;
  • argument 是一个或多个参数,它们会依次替换格式字符串中的 % 占位符。

来一个最经典的例子:

printf "hello, %s! 今天是 %d 号。\n" "linux" 15

输出:

hello, linux! 今天是 15 号。

这里的 %s 表示“这里要放一个字符串”, %d 表示“这里要放一个整数”。参数从左到右和占位符一一对应: "linux" 填进 %s 15 填进 %d 。格式字符串里没写 \n ,输出就真的不换行,这个坑我见过太多次了——新手写 printf "hello" 发现脚本输出全部挤在一行,其实不是命令坏了,是没加换行符。

还有一个容易忽略的行为:如果格式字符串里的占位符数量比参数多,多余的位置会被当作“空值”处理—— %s 会变成空字符串, %d 会变成 0。反过来,如果参数比占位符多,多余的参数会被循环使用(部分的 printf 版本会把整个格式字符串重复应用,直到参数耗尽)。这个循环行为有时候能帮你批量生成内容,但也容易造成输出比你预期的多,写脚本时要注意。

2.2 常用格式说明符:%s、%d、%f 一次讲清

格式说明符是 printf 的“填充槽”,每种类型管一种数据。我按使用频率给你拆开讲:

格式符作用典型用法示例输出示例
%s 字符串printf "%s\n" "hello" hello
%d 十进制整数printf "%d\n" 42 42
%i 等价于 %d printf "%i\n" -7 -7
%o 八进制数,无前缀printf "%o\n" 8 10
%x 十六进制数(小写)printf "%x\n" 255 ff
%x 十六进制数(大写)printf "%x\n" 255 ff
%f 浮点数,默认六位小数printf "%f\n" 3.14159 3.141590
%e 科学计数法(小写 e)printf "%e\n" 1234.5 1.234500e+03
%g 自动选择 %e 或 %f,去掉多余零printf "%g\n" 3.1400 3.14
%c 单个字符printf "%c\n" abc a
%b 带转义解释的字符串printf "%b\n" 'a\tb' a b

关于 %b 值得单独提一下。普通的 %s 会把参数里的 \t \n 当普通字符原样输出,但 %b 会先对这个参数做一次转义解释,然后再输出。所以:

printf "%s\n" 'a\tb'   # 输出字面上的 a\tb
printf "%b\n" 'a\tb'   # 输出 a tab b

这个区别在拼接带特殊字符的字符串时非常有用,比如你想把某个变量里的 \n 真正变成换行输出到文件里, %b 就会很方便。

另外,如果你在 shell 里想把一个数按八进制、十六进制显示,不需要写脚本,直接用 printf 就够:

printf "十进制 %d 等于八进制 %o、十六进制 %x\n" 255 255 255
# 输出:十进制 255 等于八进制 377、十六进制 ff

这个用途在处理权限位(chmod 的数字)或者 mac 地址、内存地址时很实用。

2.3 宽度、对齐与精度:让输出真正“对齐”的关键

%s %d 这些只是类型,真正让输出变得专业的是宽度修饰符。格式是:

%[flags][width][.precision]type

其中:

  • width :最小输出宽度,不够就补空格;
  • - :左对齐标志,默认是右对齐;
  • 0 :数字左边补 0 而不是补空格;
  • .precision :对于浮点数表示小数位,对于字符串表示最大字符数。

直接看例子:

# 右对齐,宽度 10
printf "%10s|\n" "abc"

# 左对齐,宽度 10
printf "%-10s|\n" "abc"

# 数字补 0
printf "%05d\n" 42

# 浮点数保留 2 位小数
printf "%.2f\n" 3.14159

输出分别是:

       abc|
abc       |
00042
3.14

这几个修饰符组合起来,就是所有表格对齐操作的底层基础。我自己最常用的组合是 "%-20s %8s %8.2f\n" 这种——第一列左对齐占 20 位放名称,第二列右对齐占 8 位放字符串,第三列右对齐、固定两位小数放数值。只要所有行都套同一个格式,天然就能对齐,完全不用自己数空格。

注意一点: 中文等全角字符在终端里占 2 个显示宽度,但 printf 的宽度计算是按字符数来的 ,所以如果你用 %20s 去对齐包含中文的列,实际看起来可能差几个空格。这个问题没有完美的命令行解法,常见做法是给中文列预留足够宽度,或者干脆让数据左对齐,减少右侧参差不齐的观感。

3. 转义字符:让输出真正“可控”的基础

3.1 常用转义字符速查表

printf 的格式字符串里除了格式符 % ,还有一类重要语法是转义字符。它们以反斜杠开头,表示特殊控制序列。我整理一张速查表:

转义含义说明
\n 换行最常用,没有它 printf 不换行
\t 水平制表符相当于按一次 tab
\\ 反斜杠本身想输出 \ 字符时用
\" 双引号在双引号字符串里输出 "
\' 单引号在单引号里输出 '
\a 响铃终端响一声,可以当提示音
\b 退格光标往回退一格
\r 回车回到行首不换行,常用于进度条刷新
\v 垂直制表符向下跳一行
\f 换页大部分终端忽略
\0nnn 八进制字符输出任意字符,如 \012 等于 \n
\xhh 十六进制字符 \x41 输出大写字母 a
\e esc 转义字符在部分 shell 中可用,配合 ansi 颜色码

如果想要输出百分号 % 本身,不能用转义,要写 %%

printf "进度:%%d%%\n"   # 会原样输出 “进度:%d%”

3.2 中文乱码:先分清是终端编码还是 printf 的锅

热词里有“printf中文乱码”,这个我专门展开讲一下。很多人在终端里跑 printf "你好\n" ,结果看到乱码,第一反应是命令有问题——其实多半和 printf 没关系,而是终端编码和系统 locale 不匹配导致的。

排查思路很简单:

# 1. 先看 shell 的当前语言环境
echo $lang

# 2. 再手动指定 utf-8 输出试试
printf "你好\n" | iconv -f utf-8 -t utf-8

如果终端设置的字符集是 utf-8,系统 locale 也显示 zh_cn.utf-8 ,那么 printf "你好" 应该能正常显示。反过来,如果你在 windows 上通过 ssh 连 linux,本地终端默认是 gbk/gb2312,而 linux 侧输出 utf-8,那就会看到 浣犲ソ 这种经典的乱码模样。这就是典型的“终端解码用的字符集和 shell 输出用的字符集不一致”,和 printf 命令本身一点关系都没有。

实际处理建议:

  • 优先保证终端字符集为 utf-8(主流终端默认都是);
  • 执行 export lang=c.utf-8 export lang=en_us.utf-8 来统一环境;
  • 如果手头有 gbk 编码的文件或文件名,用 iconv -f gbk -t utf-8 file.csv 转换内容,用 convmv 转换文件名;
  • 在脚本里输出中文时,尽量在脚本头部写清 export lang=zh_cn.utf-8 ,或者直接统一用英文输出,避免环境差异带来的显示问题。

还有一种“假乱码”情况:字符串里带了 ansi 转义序列(比如颜色控制码 \033[31m ),但终端没启用颜色支持,于是屏幕上出现 ^[[31m 这类垃圾字符。这个问题我放到后面颜色输出那一节细说。

3.3 颜色输出:用转义序列让脚本更直观

给输出添加颜色,在交互式脚本和调试工具里非常好用。核心原理是向终端输出 ansi 转义序列,格式是:

\033[<参数>m

printf 里写,就是:

printf "\033[31m 红色文字 \033[0m\n"

其中:

  • \033[31m :把前景色设为红色;
  • \033[0m :重置所有样式,恢复默认。

常用颜色码我列一下:

颜色前景色代码背景色代码
3040
3141
绿3242
3343
3444
3545
3646
3747

另外还有几个常用样式: 1 加粗、 4 下划线、 5 闪烁、 7 反白。可以组合用,比如 \033[1;31m 表示加粗红色。

颜色输出的实际价值在于:脚本跑完一眼扫过去,错误是红色的、警告是黄色的、正常是绿色的,人眼识别速度能快不少。但要注意,如果脚本输出要重定向到文件,或者要经过管道交给别的程序处理,那颜色转义序列会变成多余字符污染文件内容。所以有经验的做法是写一个 is_tty 判断:终端才输出颜色,非终端就输出纯文本。bash 里可以这样判断:

if [ -t 1 ]; then
    printf "\033[32m成功\033[0m\n"
else
    printf "成功\n"
fi

4. 实操案例:从命令行到脚本的典型场景

4.1 表格对齐:让 ps、du 的原始输出变得整齐

日常用 ps du df 这些命令时,输出经常是“歪”的,尤其当你把结果塞进脚本重新组织时,最容易出现列宽不齐。用 printf 可以重新定义一个整齐的表格输出格式。比如我想统计几个常用命令的路径和大小:

#!/bin/bash
commands=("bash" "ls" "curl" "python3")
printf "%-10s %8s %s\n" "命令" "大小(字节)" "路径"
echo "----------------------------------------"
for cmd in "${commands[@]}"; do
    path=$(command -v "$cmd")
    size=$(stat -c%s "$path")
    printf "%-10s %8d %s\n" "$cmd" "$size" "$path"
done

这里的关键就是 %-10s 让命令名左对齐、 %8d 让字节数右对齐。不管数据是 1 还是 1234567890,每一列都照样对齐,比你手动加空格靠谱一百倍。

同样的思路也可以用来格式化 /proc/meminfo 的关键信息,或者把磁盘使用率整理成一个人眼友好的报告。格式化脚本输出, printf + %/格式化符 的组合几乎是唯一不会出错的方案。

4.2 进度条与动态更新:\r 的妙用

在终端里做进度条,核心是 \r 回车符——它把光标移回行首但不换行,然后你用新的内容覆盖旧内容。配合 printf ,几行就能写出朴素的进度条:

#!/bin/bash
for i in $(seq 1 100); do
    printf "\r进度:%3d%%" "$i"
    sleep 0.05
done
printf "\n完成!\n"

这里 %3d 保证数字从 3 位宽度右对齐,这样 1 变成 2 时,后面不会残留上一个数字的尾巴。如果你不写 \r ,终端会一路向右刷出一长串进度百分比,乱七八糟;写了 \r ,每次更新就是原地覆盖,视觉效果干净利落。

更完善一点的进度条可以加上“当前值/总数”和简单的时间消耗:

printf "\r处理中... %d/%d" "$current" "$total"

循环结束之后千万别忘了补一个 \n ,否则最后一行进度会跟后续输出粘连,脚本看起来就很业余。这个坑我在写文件批量处理脚本时踩过不止一次。

4.3 printf 重定向:生成脚本、写配置文件

printf 和重定向结合,简直是批量生成配置文件的利器。比如我想一次性生成 100 个带编号的 yaml 配置文件:

#!/bin/bash
for i in $(seq 1 100); do
    printf "server:\n  id: %03d\n  name: node-%03d\n  enabled: true\n" "$i" "$i" > "config-$i.yaml"
done

%03d 会把 1 输出为 001 ,这样文件名和内容里的编号保持三位一致,排序时不会出现 config-2.yaml 排在 config-10.yaml 后面的问题。类似地, printf 也能用来快速构造 csv:

printf "id,name,score\n" > score.csv
printf "%d,%s,%.2f\n" "$id" "$name" "$score" >> score.csv

如果有人问“ printf 重定向和 echo >> 有什么区别”,答案是:格式化能力完全不同。echo 很难在一行里同时做到左右对齐、补前导零、保留两位小数,而 printf 只要一条格式串就全部搞定。在做日志审计、生成数据文件、初始化脚本时,这个能力会让你省很多时间。

重定向的注意事项也很简单:

  • > 是覆盖写入, >> 是追加写入;
  • printf 自己只负责生成文本,写入文件需要靠 shell 重定向;
  • 如果要把 stdout 和 stderr 都保留并分别处理,用 2>err.log 1>out.log 之类的操作,printf 的 stdout 和其他命令一样受 shell 重定向规则约束。

4.4 与管道和命令替换的联动用法

printf 经常和 xargs awk $( ) 组合使用。最常见的是把 printf 的输出通过管道交给 xargs 批量执行命令:

printf "%s\n" file1.txt file2.txt file3.txt | xargs -i {} gzip {}

另一个场景是用命令替换把格式化结果塞进其他命令的选项里。比如你想把当前时间格式化成日志文件名:

logfile="$(printf "app-%y%m%d-%h%m%s.log" $(date '+%y %m %d %h %m %s'))"

不过这里有个更简单的方案:直接让 date 命令自己处理格式:

logfile="$(date +'app-%y%m%d-%h%m%s.log')"

所以我其实更推荐在“需要把多个变量按固定格式拼成字符串”时,才用 printf 配合命令替换。比如拼接访问日志的一行:

log_line="$(printf "%s %s %s" "$ip" "$time" "$url")"

这样写可读性比用双引号直接拼接好得多,尤其当变量里可能带空格、特殊字符的时候, printf 不会因为忘记转义而把内容弄丢。

还有一个实用组合是 read 。用 printf 生成一行标准格式文本,再用管道把这一行交给 read 按字段拆分:

printf "%s %s %s\n" "apple" "banana" "cherry" | { read a b c; echo "第一个是:$a"; }

这种方式适合模拟从文件或命令输出里读取字段的场景,写测试脚本时非常好用。

5. 容易踩的坑:编译警告、编码问题与精度陷阱

5.1 警告 #223-d:function "printf" declared implicitly 是什么

热词里有一条关于编译警告的查询,提示是 warning: #223-d: function "printf" declared implicitly 。这明显是嵌入式开发场景(比如 keil mdk、iar 或某些 arm 交叉编译工具链)里的 c 语言问题,跟 shell 的 printf 命令不是一回事,但既然大家会搜到,我就顺带说透。

这个警告的意思是:你在 c 代码里使用了 printf 函数,但没有在调用前声明它。c 语言规定,函数在使用前必须要有声明(函数原型),否则编译器只能“猜测”这个函数长什么样,于是给出 warning。解决办法只有一个——在源文件开头加上:

#include <stdio.h>

因为 printf 的声明就在标准头文件 <stdio.h> 里。很多初学者(比如刚装了虚拟机、跟着教程写第一个 c 程序的同学)会漏掉这一行,或者写成了 <studio.h> (对,把 stdio 拼成 studio 的,我见过不少次),编译器就会报类似的警告甚至错误。

如果你用的是自带轻量级 printf 实现的嵌入式环境(比如某些单片机的 sdk 把 printf 重定向到了串口),那么在包含头文件之后、首次调用之前,通常还要额外处理一个事情: 实现底层发送字符的钩子函数 。比如在 stm32 的 hal 库环境中,你要重写 fputc _write 之类的函数,把 printf 的输出转发到 hal_uart_transmit ,才能在串口调试助手里看到内容。这一步不做,你的 printf 编译通过、跑起来却像哑巴一样——程序正常,可串口里什么都没有。网上流传的《告别 printf 调试》系列文章,本质上就是在讲如何用更高级的命令行交互方式(比如 letter shell)替代这种裸串口调试,但底层发送链路的思路是一脉相承的。

5.2 printf 中文乱码的真正原因与处理思路

中文乱码这个话题在前面的转义章节已经提过,这里我再补充一个更细节的实测场景。假设你在 locale 为 en_us.utf-8 的系统上执行:

printf "你好,世界\n"

如果终端是 utf-8 编码,输出正常。如果终端被设成了 c (posix)环境,你可能会看到一堆类似 \344\275\240\345\245\275 的八进制转义被原样打出,或者干脆是乱码。这是因为 locale 环境变量影响的是“shell 和工具如何解释字节序列”,而不是 printf 命令本身会做什么转换。 printf 只会把参数中的字节原样送到 stdout,至于这些字节如何显示,是终端解释器的事。

所以中文乱码的排查顺序是:

  1. 确认终端字符集:gnome terminal、vs code、xshell 等工具都有编码设置,统一为 utf-8;
  2. 确认系统 locale:执行 locale 命令,看 lang lc_all ,最好让它们一致;
  3. 检查文件本身编码:如果是 windows 上编辑的脚本文件,可能是 gbk 编码,用 file -i script.sh 查看,然后用 iconv 转换成 utf-8;
  4. 检查脚本中的 heredoc、字符串拼接两边的引号是否匹配,有些“乱码”其实是引号歧义导致截断产生的。

如果你只是想临时验证输出是否正常,可以用一条命令把编码强转:

printf "中文测试\n" | hexdump -c

如果看到 e4 bd a0 e5 a5 bd (utf-8 编码的“你好”),那说明 printf 输出的字节是正确的,问题一定出在终端显示环节。

5.3 浮点数精度:为什么 printf "%.3f" 会显示 0.000

有次我在脚本里做除法:

a=1
b=3
printf "%.3f\n" $((a / b))

输出是 0.000 ,我当时愣了一下——这属于 shell 整数运算的经典陷阱。 $((a / b)) 是整数除法,1 除以 3 的结果直接截断成 0, printf 再厉害也没办法把已经变成 0 的整数变回小数。要算浮点数,得用 bc awk 或者 python3

awk 'begin {printf "%.3f\n", 1/3}'
# 输出 0.333

另外一个浮点数陷阱是 printf 解析浮点数时的精度问题。shell 的 printf 在内部通常用 c 语言的浮点类型(double)来解析,对于大多数业务场景足够,但如果你在做高精度计算(比如金融金额、哈希校验值),建议直接上 bc -l python3 十进制运算,别用 printf 硬扛。

还有一个小坑: %d 如果收到一个非整数内容,bash 的 printf 会有未定义行为——有的版本会报错,有的版本会输出 0。所以我在脚本里经常用 %s 打印本应是整数的变量,等确认数据干净了再改用 %d

5.4 单引号、双引号和 %%:格式字符串的转义规则

printf 时,格式字符串该用单引号还是双引号,很多人没仔细想过。简单规则是:

  • 如果格式串里只有普通字符和 % \ ,单双引号都一样;
  • 如果格式串里还要插入 shell 变量,必须用双引号,否则变量不会展开;
  • 如果格式串里的 $ 是字面意思,不想让 shell 解析,用单引号。

举例:

name="world"
printf 'hello, %s\n' "$name"   # 单引号格式串里没有 $,正常
printf "hello, $name\n"        # 双引号格式串里的 $name 会被展开成 world

但如果你写了:

printf "hello, %s\n" $name    # 没加双引号的 $name,就等着踩坑

$name "a b c" 时,它会被 shell 拆成三个参数, printf 会执行循环填充,输出三行或者一行里夹带额外内容。最佳实践是: 所有参数变量都加双引号 。这条规则适用于所有 shell 命令,不只是 printf

另外一个常见问题是百分号 % 。如果你想输出 100% ,直接写 printf "%s\n" "100%" 没问题,因为 %s 的格式串里 "100%" 只是普通参数,不会被二次解析。但如果你把 100% 放在格式串自身里,比如 printf "100%\n" ,那 % 会被解读成格式说明符的开头,后面没有合法字母,bash 会直接报错:

bash: printf: `\n': invalid format character

这时你要写成 printf "100%%\n" ,用两个百分号输出一个字面 %

6. 进阶玩法:把 printf 当脚本里的瑞士军刀

6.1 批量生成序列与重复模板

printf 配合循环可以快速生成序列或重复模板。比如生成 001 到 050 的编号:

for i in $(seq 1 50); do
    printf "%03d " "$i"
done
echo

输出:

001 002 003 ... 050

如果你要生成 json 数组模板,也可以这样:

printf '{"id":"%d","name":"%s"},' "$i" "node-$i"

然后拼成一个大的 json 文件。虽然更严谨的做法是用 jq ,但在一些受限环境里, printf 的风格演练还是很有用。

还有一种玩法是用 printf 输出固定长度的分隔线。比如在脚本日志里画一条 60 个字符宽的分隔线,我通常这样写:

printf '%0.s-' {1..60}; echo

printf '%0.s-' 的意思是:不打印参数( %s 的精度是 0),但用 - 作为被忽略的内容?严格来说这行利用了 printf 的循环特性—— {1..60} 展开成 60 个参数,格式串 '%0.s-' 被循环使用,每次都输出一个 - ,最终得到 60 个连字符。这个写法有点绕,但实测很稳定。如果你觉得读着费劲,直接用一个字符串变量也行:

separator="------------------------------------------------------------"
printf "%s\n" "$separator"

两种我都用过,看个人习惯。理解背后的原理之后,用的时候心里有底。

6.2 进制转换与字符码查询

日常在终端里临时查 ascii 码、做进制转换, printf 是极好的工具:

# 十进制转十六进制
printf "%x\n" 255        # 输出 ff

# 十六进制转十进制
printf "%d\n" 0xff       # 输出 255

注意, %d 接受 0xff 这种带前缀的十六进制写法,因为它会按 c 语言的数值规则解析。这在你查颜色代码、mac 地址、内存偏移量时很有用。

另一类操作是字符码查询。想查一个字符的八进制、十六进制编码:

printf "%d\n" "'a"        # 输出 65,这是技巧性的写法:参数 "'a" 表示字符 a 的 ascii 码
printf "%x\n" "a"         # 某些 shell 版本会输出 41,但不是所有版本都支持,谨慎使用

如果你想从十六进制字节还原成可见文本,可以这样组合:

printf "\x41\x42\x43\n"   # 输出 abc

这在处理二进制协议调试、加密字符串解密场景时会用到。比如在内核模块或嵌入式开发里,经常要手拼一长串十六进制数据, printf "\x.." 直接把二进制字节输出到文件或终端,比用 echo 可靠得多。

6.3 printf 调试法与更现代的交互式命令行

很多从嵌入式转过来的朋友可能习惯用 printf 加串口输出做调试——在关键路径上打点,看程序走到哪里、变量值是多少。这种“打桩调试法”在资源受限的单片机上确实是最简单的手段,而且配合 printf 重定向到串口、再在 pc 端用串口助手看日志,大多数问题都能快速定位。

但如果你维护的是一个交互式命令行程序(比如带菜单的测试工具),打桩输出的日志和交互提示会混在一起,体验就很差。这也是为什么社区里会有人做 letter shell 这类交互式命令行组件:它把命令解析、参数补全、历史记录这些能力都封装好,你在嵌入式设备上就能用上类似 linux shell 的交互体验。 printf 这时候反而退居二线,用来做底层的日志输出,而不是和用户交互。我建议的思路是: 底层调试用 printf 打点,对外交互用封装好的命令行组件 ,两者各管一摊,互不干扰。

回到 linux 环境本身, printf 在调试 shell 脚本时也是利器。比如打印数组内容:

arr=("apple" "banana" "cherry")
for item in "${arr[@]}"; do
    printf "[%s]\n" "$item"
done

这样一眼能看到数组里的每个元素有没有被正确读取,尤其元素带空格时,printf + 双引号能保证每个元素被完整打印,不会出现 for 循环按空格拆开的错觉。

如果你是在调试 c/c++ 或者内核模块,那 printf 对应的角色就变成了 printk / printf 打点。但无论如何, 把日志格式统一、带级别标识、带时间戳 都是通用好习惯,这一点和 printf 的格式化能力密不可分。用 printf 在日志开头拼时间、级别、文件名和行号,比裸写乱糟糟的字符串要清晰得多,排查问题时一眼就能定位日志来源。

最后再分享几个日常写脚本时养成的习惯:能用 printf 就不用 echo ;所有变量引用都加双引号;格式化输出时先想清楚对齐方向和宽度,再动手写格式串;凡是输出要重定向到文件的,一律禁用颜色代码;凡是中文参与对齐的,预留足够宽度,别追求像素级完美。踩过几次坑之后你会发现, printf 虽然看起来就一个命令,却是 shell 脚本输出质量的分水岭——用得好的人,日志和表格清爽得像官方工具;用不好的人,永远是满屏乱糟糟的字符串拼接。希望这篇能帮你跨过这道分界线。

以上就是从入门到精通详解linux中printf命令用法的完全指南的详细内容,更多关于linux printf命令的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com