开始学习一块新开发板时很多人第一件事是去翻原理图、点亮LED我反而是先把Linux文件系统完整摸了一遍。IMX6ULL这块板子看起来是硬件主导实际上后面所有驱动、应用、交叉编译每一步都绕不开文件目录的操作。这篇笔记是IMX6ULL学习系列的第一篇就聚焦在Linux的文件目录结构、目录相关命令以及我在板子上实际操作时碰到的各种情况。适合刚拿到板子、还没理清Linux目录逻辑或者对嵌入式Linux环境下目录使用还比较模糊的朋友。1. 嵌入式开发为什么先要啃文件目录这套东西1.1 IMX6ULL开发环境里的目录不只是“放文件的地方”IMX6ULL板子上跑的是精简过的Linux系统文件目录比Ubuntu桌面版少很多但骨架是完整的。所谓“骨架”指的是/bin、/usr、/etc、/dev、/proc、/sys这些一级目录都在只是里面的内容被裁剪过。嵌入式系统最终要烧进SD卡或者EMMC文件系统就是整个系统的“住处”。驱动要加载、应用要运行、配置要读取全都靠目录去定位。很多初学者会问我直接操作ARM芯片寄存器不就行了实际操作中裸机开发确实可以直接操作地址但一旦上了Linux你写App也好写驱动也好最后都会落到“某个文件”上。Linux的设计哲学就是“一切皆文件”GPIO是文件、串口是文件、内存映射也是文件。你如果不理解目录这一层后面看设备树、看驱动框架代码的时候会非常别扭。我自己的体会是嵌入式开发过程中大约有七成时间不是在写代码而是在跟命令行打交道而命令行有一半操作是在处理目录和路径。这条基本功打不牢后面做NFS挂载、交叉编译、启动脚本调试每一步都会被卡一下。1.2 从Windows思维切换过来的三个关键差异Windows用盘符C:、D:来分门别类每个盘有自己的根Linux只有一个根就是“/”。这不是细节差异是整套路径逻辑的起点。你在IMX6ULL板子上看到的所有目录都挂在这个“/”下面外部存储设备比如U盘、SD卡、网络文件系统也不是像Windows那样自动成为新盘符而是通过“挂载”这个动作接到根目录下的某个子目录里。第二个差异是大小写敏感。IMX6ULL的开发环境在Linux上目录名区分大小写/etc和/ETC是两个完全不同的地方。在Windows上习惯了随便大小写的人初期经常在这上面翻车配置文件写错路径服务起不来查了半天发现大小写不对。第三个差异是路径的表示方式。Windows用反斜杠“\”Linux用正斜杠“/”。在命令行里输入路径时要用/这个看起来无所谓真敲命令的时候却能省下不少麻烦。还有一点很实际Windows下相对路径和绝对路径的概念比较弱大多数人打开“我的电脑”点进某个文件夹而在Linux下你在哪个目录、用什么路径去定位目标文件直接决定了命令能不能执行成功。2. Linux文件目录结构拆解嵌入式版2.1 标准目录树与IMX6ULL精简后的差别标准的Linux文件系统遵循FHSFilesystem Hierarchy Standard规范也就是文件系统目录结构标准。桌面发行版为了通用性和多用户场景目录会非常齐全IMX6ULL这种嵌入式板子一般是用BusyBox配合Buildroot或者Yocto生成的rootfs裁剪力度很大。一个完整的Ubuntu系统顶层大概会有20多个目录而IMX6ULL板子上的顶层目录通常更精简。我拿手头这块正点原子IMX6ULL板子上的文件系统举例开机后进入Shell执行“ls /”看到的目录大概是下面这些bin dev etc home lib linuxrc mnt proc root run sbin sys tmp usr var对比一下Ubuntu少了boot、media、opt、srv这些目录。这很正常嵌入式rootfs不需要通用性能跑起来、空间占用尽量小是首要目标。启动文件、内核镜像都放在单独的分区不一定挂在根文件系统上。以下是我整理的标准目录和嵌入式开发中各自的作用目录标准作用IMX6ULL场景中的实际意义/bin基础用户命令存放BusyBox里的基本工具比如ls、cp、mv/sbin系统管理命令启动、文件系统修复等管理员工具/etc系统配置文件网络、启动脚本inittab、fstab都在这/dev设备文件GPIO、LED、串口等硬件对应的操作入口/proc内核运行时信息查看CPU、内存、内核参数/sys内核设备模型操作GPIO、PWM等后面驱动开发高频使用/usr用户程序与库应用装这里但嵌入式下经常和根目录合并/lib共享库存放C库和驱动模块需要的依赖库/tmp临时文件掉电不保留、重启清空/var可变数据日志、缓存嵌入式下经常是tmpfs2.2 /dev、/proc、/sys这三个目录要单独拎出来讲这三个目录对于嵌入式开发特别重要因为它们不是一个“存放静态文件”的普通目录而是一个动态生成、与内核交互的窗口。/dev是设备文件目录。在Linux下应用程序操作一个硬件设备就是打开/dev下面的某个文件节点然后做读写。IMX6ULL上有串口设备/dev/ttyS0、/dev/ttymxc0LED可能有/dev/leds按键可能注册成/dev/key。嵌入式板子启动过程中如果/dev下面某个设备节点不存在对应的硬件功能基本就废了。老式的做法是手动mknod创建设备节点现在一般靠devtmpfs启动时自动生成或者驱动加载后注册。/proc是一个“虚拟文件系统”里面的内容不是磁盘上的文件而是内核运行时的数据。比如/proc/cpuinfo能直接读到CPU信息/proc/meminfo能读内存使用情况/proc/modules能看当前加载了哪些驱动模块。在IMX6ULL上调驱动时我最常用的操作之一就是“cat /proc/interrupts”看中断有没有触发。/sys是另一个虚拟文件系统但内容更偏向设备和驱动模型。比如/sys/class/leds下面会列出所有LED设备进去之后有brightness文件往里面写1就是点亮写0就是熄灭。后续做GPIO控制实验时很多人不直接写驱动先通过/sys/class/gpio来操作引脚就是这个道理。2.3 嵌入式文件系统的“只读”思维嵌入式设备上根文件系统有时候是只读的比如做成squashfs这种压缩只读文件系统出厂后防止用户乱改。这在IMX6ULL上很常见产品固件不希望被误删就把根文件系统设置为只读读写区域单独挂到/var或者/data这样的分区上。这个习惯直接影响你用目录的方式你不能想往哪个目录写就往哪个目录写。比如/tmp通常是可写的因为它本质是内存文件系统tmpfs重启后清空/var也可能是tmpfs但/bin、/usr这种目录很可能没有写权限。所以碰到“Permission denied”时先别急着怪系统先想想这个目录的设计定位是什么只有可写目录才会给你写入机会。3. 目录相关命令实操要点3.1 定位当前目录pwd 与 cdpwdprint working directory是最基础的命令作用是显示当前所在目录的绝对路径。嵌入式项目里你经常需要知道“我现在在哪”尤其是通过串口登录板子后Shell默认落在/root或者/home/root如果你之前执行过cd很容易迷失路径。rootimx6ull:~# pwd /rootcdchange directory是切换目录的命令。最常用的几种写法cd / # 切换到根目录 cd .. # 回到上一级目录 cd ~ # 回到当前用户的 home 目录 cd - # 切换到上一次所在的目录我特别提一下“cd -”这个在板子上调试时非常实用。你从/app目录临时去/etc看个配置看完想回/app继续编译直接输“cd -”就回去了不用重新打一长串路径。3.2 查看目录内容ls 的常见组合ls是最常打的命令没有之一。单独敲ls只能看到当前目录下的非隐藏文件信息量太少实际工作中基本都是组合参数用ls -l # 长格式显示含权限、属主、大小、修改时间 ls -a # 显示隐藏文件以.开头的文件 ls -lh # 人类可读大小比如显示20K而不是20480 ls -lt # 按修改时间排序最新排前面-l输出的第一列是权限字符串比如“drwxr-xr-x”第一位d表示是目录后面9位分成三组分别对应所有者、所属组、其他人的读/写/执行权限。看懂这个后面遇到权限问题能快速定位。在IMX6ULL板子上文件系统里的很多目录内容不多用ls -l一眼就能看到关键信息。比如查看/dev下面的设备节点ls -l /dev/ | grep ttymxc能直接看到串口设备对应的主设备号和次设备号。3.3 创建和删除目录mkdir 与 rmdirmkdir就是make directory创建目录。最实用的参数是-p可以一次性创建多级目录mkdir /home/project/drivers mkdir -p /home/project/drivers/platform第二条命令会把drivers和platform两级目录都建出来如果drivers已经存在也不会报错。嵌入式开发中经常需要一次性创建一整套项目目录结构-p参数能少敲很多命令还能避免“目录不存在”的报错。rmdir用于删除空目录只能删除空目录目录里有文件就会报“Directory not empty”。因为实际工作中很少只删空目录所以rmdir用得不多更常用的是“rm -r”。但这里要特别提醒rm -r是删除目录及其全部内容没有后悔药板子上的目录删错了经常只能重新刷机。新手阶段我建议先用rmdir它逼着你确认这个目录确实是空的不那么容易误删。3.4 移动、复制目录mv 与 cp把文件或者目录从一处搬到另一处用mv。它同时承担“重命名”的功能因为Linux下的重命名本质就是把这个路径移到另一个路径下mv old_dir new_dir # 重命名目录 mv /src/dir /dest/dir # 移动目录 mv -f source target # 强制覆盖cp复制目录时必须加-r参数才能递归复制cp -r /app /backup/app_backup很多从Windows转过来的人第一次复制目录直接“cp 目录A 目录B”结果报错“omitting directory”。这就是因为没加-r导致的。嵌入式系统中需要备份整个rootfs或者把交叉编译好的库复制到/lib目录下时cp -r是高频操作。3.5 查找目录和文件find、tree、dufind是Linux查找命令里最强大的一个基本格式是find [查找路径] [匹配条件] [动作]在IMX6ULL开发中使用频率最高的是按名字查找find / -name *.ko # 在根目录查找所有内核驱动模块 find /etc -name inittab # 查找指定的配置文件 find /sys -type d -name leds # 查找类型为目录且名为leds的路径-name支持通配符*表示任意字符?表示单个字符。我第一次在板子上找驱动模块时就是靠这条命令找到编译生成的.ko文件是不是已经放进/lib/modules下的正确位置。tree命令是树状展示目录结构但嵌入式板子的BusyBox默认不一定带这个命令Ubuntu交叉编译环境里通常需要apt install tree。它的价值主要在项目规划阶段比如你要搭一个应用工程目录先列出树状图再对照创建。du命令用于统计目录大小排查空间不足时很有用du -sh /var/log # 查看某个目录总大小 du -h --max-depth1 /usr # 只统计一层子目录的大小嵌入式板子的Flash或者SD卡空间有限经常出现“No space left on device”。用du找到占用最大的目录然后决定清理这是排查磁盘问题的基础路子。4. 在IMX6ULL开发板上实操从开机到目录漫游4.1 连接板子的两种方式与初始环境IMX6ULL板子到手后最常用的连接方式是串口终端和SSH网络登录。串口连接用USB转串口线Windows下用MobaXterm或者SecureCRTLinux下用minicom或者picocom。波特率一般是1152008N1。接好线、上电串口终端里就能看到Bootloader日志和文件系统启动信息。SSH则需要板子和电脑在同一网段板子上开启SSH服务后用MobaXterm或者命令行直接“ssh root板子IP”登录。登录成功后Shell提示符一般是rootimx6ull:~#root表示当前用户imx6ull是主机名~表示当前在root用户的home目录就是/root。这个提示符里其实已经把“当前路径”告诉你了后面实操过程中每敲一条命令之前习惯性看一眼提示符能少走很多弯路。4.2 做一个完整的目录探索实操我在板子上做了一次完整的目录探索目的是把前面讲的一级目录都看一遍并理解它的实际内容。整个过程记录在下面这个可以作为你拿到板子后照做的“第一课”。先看当前路径rootimx6ull:~# pwd /root查看根目录下的所有一级目录rootimx6ull:~# ls -l / total 184 drwxr-xr-x 2 root root 4096 Jan 1 00:00 bin drwxr-xr-x 3 root root 4096 Jan 1 00:00 dev drwxr-xr-x 4 root root 4096 Jan 1 00:05 etc drwxr-xr-x 3 root root 4096 Jan 1 00:00 home ...Jan 1 00:00这个时间戳很有意思说明文件系统镜像是在制作时固化的不是实时生成。嵌入式板子在没联网校时之前文件时间经常是这种“出厂时间”。进入/etc目录看启动配置rootimx6ull:~# cd /etc rootimx6ull:/etc# ls -l/etc目录里会有inittab、fstab、init.d这些文件。inittab是BusyBox init进程的启动配置定义了系统启动后要跑哪些程序fstab是文件系统挂载表规定了哪些设备要挂到哪些目录。嵌入式系统开机流程调试基本都是围绕这两个文件展开。再切到/sys目录下操作一个硬件rootimx6ull:/sys/class/leds# ls -l在这个目录下会看到板载LED的设备项比如“red”或者“sys-led”。进入对应目录查看brightness文件往里面写入1会让LED点亮rootimx6ull:/sys/class/leds/sys-led# echo 1 brightness这个操作虽然简单却是“目录设备文件”理念的极致体现——你用操作普通文本文件的方式完成了一次硬件控制。4.3 交叉编译环境下的三套目录Windows侧、Linux侧、板子侧IMX6ULL开发过程中你往往同时面对三套路径Windows上放代码的目录、Ubuntu交叉编译环境下的目录、板子上的目标目录。这三者不能搞混否则就会出现“我在Windows能看到文件编译却说找不到”的尴尬。我自己的习惯是在Ubuntu下建一个专门的workspace目录用来存放所有工程代码比如“/home/用户名/work/imx6ull”然后把Ubuntu的该目录通过NFS共享给板子挂载这样板子和开发机共享一份代码。好处是板子上修改代码Ubuntu侧立即同步否则每次都要通过TFTP或者U盘拷贝效率极低还容易版本混乱。这其中的核心思想就是目录是“逻辑组织”不是“物理边界”。同一个工程在Windows上看是E:盘某个目录在Ubuntu上是/home/work目录在板子是/mnt/nfs目录本质是同一份东西的不同视图。你的心智模型里如果建立了“目录就是路径别名”的概念处理起这三套目录来就不会乱。5. 常见问题与排查技巧实录5.1 常见报错速查表以下是我在IMX6ULL目录操作中遇到的典型问题以及对应的处理方式问题现象根本原因解决方式Permission denied当前用户没有目标目录写权限切换root用户检查目录权限No such file or directory路径写错或符号链接断裂用pwd确认当前位置用ls检查各级路径Not a directory把文件当目录用cd进入用ls -l确认目标类型Directory not emptyrmdir删除非空目录改用rm -r或者先清空内部文件No space left on deviceFlash或内存满了用du找出大目录清理tmp或日志Too many open files打开了太多文件句柄检查是否重复打开设备节点调高ulimit5.2 断掉的软链接嵌入式镜像里的隐藏炸弹符号链接在嵌入式系统里用得非常频繁例如/bin/sh可能是指向busybox的软链接/lib可能指向/usr/lib。制作rootfs镜像时如果软链接指向的目标路径不存在或者链接本身没打包进镜像就会出现“No such file or directory”的诡异报错。排查方法是先看文件类型ls -l /bin/sh输出结果里会显示“/bin/sh - busybox”这样的信息。如果箭头后面的目标带深红色通常说明链接断裂。嵌入式环境里我遇到过编译好的应用放在/app下它依赖libm.so.6而板子上的/lib目录里没有这个软链接结果程序一启动就报“file not found”。解决方式就是找到交叉编译器自带的库目录把libm.so.6软链接复制到板子的/lib下。5.3 相对路径与绝对路径的切换陷阱写嵌入式应用的启动脚本时最坑的一个坑是工作目录不确定。用绝对路径写的脚本无论从哪个目录启动都稳定用相对路径写的脚本在rcS里启动和在命令行手动启动结果可能是两回事。我踩过的一个实际例子板子开机自动启动某个QT应用脚本里写的是“./app”开机后应用起不来日志显示找不到程序。排查后发现init进程启动脚本时的工作目录是根目录“/”脚本里“./app”实际指向“/app”但这个应用其实被放在了“/usr/bin/app”。改成绝对路径或者先cd到目标目录再执行问题就解决了。在脚本里稳妥的做法是先执行cdcd /home/root/myapp ./app 这就避免了猜当前工作目录的问题脚本从哪里执行都不会出错。5.4 误用rm -rf的补救与预防嵌入式板子上没有回收站rm -rf误删之后基本等于需要重新刷机。我在Ubuntu交叉编译环境里有一次想清掉一个旧的build目录本来要打“rm -rf build-old”结果打成了“rm -rf build”把正在用的源码目录直接删了连带几个写好的驱动源文件一起没了。还好有git提交记录不然那一天的活就白干了。这个教训引发的习惯是删除目录之前先“ls -ld”看一下完整路径确认路径末尾确实是你想删的那个目录名再配合“find 路径 -maxdepth 0”确认路径存在。养成打完整绝对路径的习惯少用那种比较模糊的“build”字样。另外重要源代码务必纳入版本管理板子上的编译产物就算误删至少可以从代码里重新生成。6. 关于下一步的一些实践建议IMX6ULL的Linux学习目录这块是地基但不要停留在地基上。建议你在完成上述目录探索后马上干两件事一是把/etc/inittab和/etc/fstab这两个文件完整读一遍不认识的配置项就去查这两个文件能让你理解系统“启动之后凭什么挂载这些目录”二是尝试在板子上的/tmp目录写一个临时脚本练习用vim编辑、用bash执行的过程把目录操作和命令使用串起来。还有一个小操作值得练习把一个SD卡插入IMX6ULL板子后观察它自动挂载到了哪个目录通常是/media或者/mnt再用mount命令手动卸载、重新挂载到自定义目录。这个实验能把“挂载”这个概念完全吃透之后做NFS调试、调试U盘启动系统都会顺利很多。文件目录本身没什么高深技术但它决定了你之后写驱动、调应用时“站在哪里看系统”的视角。IMX6ULL这块板子的优势在于它把Linux内核、驱动和硬件的关系压缩在一块小小的开发板上你看到的每个目录背后都有对应的硬件逻辑这种“看得见摸得着”的学习路径是纯软件环境给不了的。下一篇我会继续写Linux文件操作命令和Vim的使用毕竟在板子上改配置、写脚本、编译代码这三样是每天的必修课。