HDFS的Shell命令是每天都要用的,但很多人往往只记住hdfs dfs -ls和-put这几个,遇到权限拒绝、副本数异常、磁盘空间统计不准时就开始瞎猜。今天我把日常运维中最常用的HDFS Shell命令全部拉一遍,按“浏览、传输、管理、排错”四个维度拆开讲,每条命令都配上真实的终端输出示例(你把它当成截图看就行),同时把我这些年踩过的坑一并交代清楚。无论是刚接触Hadoop的开发者,还是需要维护生产集群的运维朋友,这篇内容都能给你一份可以直接照做的操作手册。
1. 环境准备与命令基础
1.1 确认HDFS可用性
在敲任何Shell命令之前,先确认集群状态。我习惯用一条组合命令快速判断:
hdfs dfsadmin -report | head -20正常输出会显示Live datanodes的数量、容量、剩余空间等信息。如果你看到Safe mode is ON,说明集群处于安全模式,很多写操作会失败,需要先等待安全模式退出,或者手动执行hdfs dfsadmin -safemode leave。
除了dfsadmin,也可以直接查看根目录是否可用:
hdfs dfs -ls /这个命令能通,说明NameNode的RPC服务正常,基本的读路径没问题。
1.2 命令格式与常用前缀
HDFS Shell命令的完整写法有两种,很多人被搞晕:
hdfs dfs <command>hadoop fs <command>
早期版本里hadoop fs指向FileSystem的通用文件系统接口,hdfs dfs则是针对HDFS的实现。在现代Hadoop发行版里,两者基本等价,但hdfs dfs更语义化,官方也更推荐。我统一用hdfs dfs,你们在写脚本时也尽量保持一致。
命令的通用结构是:
hdfs dfs -命令名 参数参数分为HDFS路径参数与命令专属选项。路径可以是绝对路径(如/user/data),也可以是相对路径(相对于当前用户的家目录/user/<username>)。相对路径的情况容易出错,建议在脚本里全部使用绝对路径。
1.3 内置帮助:不要背选项
HDFS自带的帮助信息非常齐全,完全不用死记硬背。看某个命令的用法:
hdfs dfs -help ls会输出ls的用法、选项和示例,包括-C(不打印文件名)、-d(显示目录本身)、-h(人类可读大小)、-R(递归)等。
HDFS的-help输出比网上很多博客都准确,而且会随版本更新。遇到拿不准的选项,先敲一下帮助。生产环境里我见过有人用-ls -R与-ls -r混淆,前者是递归,后者是反转排序。多看一眼帮助能省几十分钟排查时间。
2. 文件系统浏览与查询命令详解
2.1 列出目录与递归遍历
最基础的命令是ls:
hdfs dfs -ls /user/hive/warehouse输出示例:
Found 4 items drwxr-xr-x - hive hive 0 2025-05-10 10:00 /user/hive/warehouse/login_logs drwxr-xr-x - hive hive 0 2025-05-10 10:01 /user/hive/warehouse/order_detail -rw-r--r-- 3 hive hive 2048000 2025-05-10 10:02 /user/hive/warehouse/README从输出中能读到一组关键信息:文件权限、副本数(注意目录显示为-,文件的副本数是一个数字,这里是3)、属主和属组、文件大小、修改时间、路径。
只看权限不看副本数,可能是不少新手的习惯,但副本数恰恰是判断数据可靠性的重要指标。如果生产文件副本数变成1,意味着HDFS丢了一块物理磁盘,这份数据就面临风险。后面我会专门讲setrep调整副本。
递归查看整个目录树用:
hdfs dfs -ls -R /data它能列出所有子目录和文件,输出量通常很大,建议配合grep过滤:
hdfs dfs -ls -R /data | grep "part-00000"只想看目录本身而不展开内容,用-d:
hdfs dfs -ls -d /user/hive只输出一行,用于判断路径是否存在以及它的权限信息,在脚本判断目录是否存在时非常实用:
if hdfs dfs -ls -d /tmp/test >/dev/null 2>&1; then echo "目录存在" else echo "目录不存在" fi-C选项会省略目录列表首行的Found X items信息,只输出条目,方便脚本做纯路径处理。
2.2 查看目录大小与数据节点容量
磁盘告警时,我们最想知道“某个目录到底占了多少空间”。du命令派上用场:
hdfs dfs -du -h /user/hive/warehouse-h人类可读,输出包括文件本身大小与总副本大小:
18.5 K 55.6 K /user/hive/warehouse/README第一列是单副本大小,第二列是总副本大小。对于一份副本数为3的文件,总副本大小是实际物理占用,也是真正会被计费的空间。磁盘快满时重点关注第二列。
区分目录与文件,如果想看目录下所有文件汇总,可以这样:
hdfs dfs -du -s -h /user/hive/warehouse-s输出总和,一行搞定:
1.2 G 3.6 G /user/hive/warehouse集群整体的容量用df:
hdfs dfs -df -h /输出类似:
Filesystem Size Used Available Use% hdfs://namenode:8020 10.0T 6.2T 3.5T 62%注意,HDFS的df显示的是逻辑容量,实际可写容量还会受副本策略、目录配额限制。有时你看到Available很大,但往某个目录写文件却报“Name node is in safe mode”或者“quota exceeded”,就是因为目录配额或文件数配额在起作用。
2.3 查看文件状态与块信息
stat命令可以获取文件或目录的详细元数据,一次输出所有属性:
hdfs dfs -stat "%F %b %o %n %y" /user/hive/warehouse/README格式化参数对照:
%F:文件类型(file/directory)%b:占用的块数%o:块大小(字节)%n:文件名%y:修改时间
实际输出可能是:
regular file 2 134217728 README 2025-05-10 10:02:33块数2表示这个文件被切成了2个块,块大小134217728对应128MB。判断小文件问题的时候,这个命令比ls更直观。
如果要看每个块的物理分布情况,用hdfs fsck:
hdfs fsck /data/file.bin -files -blocks -locations输出会列出每个块位于哪些DataNode上,还会提示是否缺块。这个命令不属于Shell常用范围,但排查数据倾斜和副本丢失时非常有用。
2.4 查看文件内容:cat、text、tail
小文件内容查看可以用cat:
hdfs dfs -cat /data/log/access.log.20250510它会直接输出全部内容,适合小文本。如果文件很大,千万别直接cat,否则会把终端刷爆。更安全的是tail:
hdfs dfs -tail -n 200 /data/log/access.log.20250510tail只读取文件末尾的指定行数,默认是1KB。注意它不支持-f实时跟踪,也没有-n之外的行数控制(有些版本支持可忽略)。
对于SequenceFile、Parquet这类二进制格式,直接cat会输出乱码,用text命令可以尝试解析文本内容:
hdfs dfs -text /data/seq/output.seq它会基于数据本身的压缩格式(如gzip、snappy)自动解压并输出文本,比cat更智能,排查压缩文件内容是否正常时很实用。
3. 文件上传与下载操作实战
3.1 本地文件放入HDFS:put、copyFromLocal、moveFromLocal
put是使用频率最高的写命令:
hdfs dfs -put /local/path/file.txt /user/data/put支持一次上传多个源文件到目标目录:
hdfs dfs -put a.txt b.txt c.txt /user/data/也可以把本地目录整个上传:
hdfs dfs -put /local/dir /user/data/copyFromLocal与put基本一致,但更强调“从本地复制过去”,在一些发行版里两者行为没有区别。我通常用put,因为它可以接受stdin输入,比如:
echo "hello hdfs" | hdfs dfs -put - /user/data/stdin.txt这里的-表示标准输入,在某些流式写入场景里非常实用。
moveFromLocal会删除本地文件,相当于迁移而不是复制:
hdfs dfs -moveFromLocal /local/file.txt /user/data/这个命令在本地磁盘空间不足时比较有用,但要注意:如果HDFS写入失败,本地文件会被删除吗?实测在某些版本里会存在风险,所以生产环境我很少用,宁可用put确认成功后再手动删本地文件。
上传大文件时要特别注意副本数与带宽。默认3副本,如果网络带宽有限,可以考虑上传后临时降低副本数,或者直接用setrep调整,而不是在上传过程中设置参数(上传时的-D dfs.replication=2只影响该次写入):
hdfs dfs -D dfs.replication=2 -put bigfile.bin /data/但这会导致该文件刚写入时只有2副本,后续还需要手动调整,实际上并不比先传完再setrep更优。生产中更稳妥的做法是默认副本写入,再通过setrep统一调整。
3.2 HDFS文件下载到本地:get、copyToLocal
下载用get:
hdfs dfs -get /user/data/file.txt /local/dir/如果目标目录存在,文件会放到该目录下;如果目标路径不存在,则作为新文件名保存。多个文件下载必须指定一个目标目录:
hdfs dfs -get /user/data/a.txt /user/data/b.txt /local/dir/copyToLocal与get类似,但get还支持-crc选项来校验校验和。我发现很多人在使用get时忽略了文件版本问题:HDFS上文件可能正在被其他作业写入,直接get可能拿到不完整数据。如果文件正在被事务写入,最好确认写入完成后再下载。HDFS在写文件过程中会临时生成带_COPYING_后缀的文件或BLOCK信息,get时看到文件列表里有_COPYING_就说明还没写完。
另一个冷门操作:从stdin写入HDFS,利用管道直接下载并压缩:
hdfs dfs -cat /data/file.txt | gzip > local.gz这种组合命令可以避免本地多个临时文件,但要注意管道断开时不产生残留。
3.3 追加数据:appendToFile
向HDFS已有文件追加数据,用appendToFile:
echo "new line" | hdfs dfs -appendToFile - /data/log.txt也可以合并多个本地文件为一个HDFS文件:
hdfs dfs -appendToFile local1.txt local2.txt /data/merged.txt追加操作需要文件支持写,且集群必须开启dfs.support.append(高版本默认开启)。不过注意,HDFS的追加写存在一定的性能损耗,且对文件块会生成新的写链,经常追加会导致文件块数量增多、产生大量小块问题。我自己见过一个日志文件被频繁appendToFile,块数量从1个涨到上千个,NameNode内存压力直接上升。所以如果需要高频追加,建议改成写新文件,再定期合并。
3.4 大文件传输的高效姿势
海量小文件是HDFS的大敌。上传大量小文件时,比如几千个几十KB的文件,直接一个个put会降低NameNode吞吐。我通常先打包再上传:
tar czf logs.tar.gz logs/ hdfs dfs -put logs.tar.gz /data/在文件落到HDFS后再解压,但HDFS上没有直接解压的命令,要么用作业处理,要么用tar流的方式配合Streaming工具。简便做法是只保留tar包,需要哪些小文件再通过get下载后解压。虽然多一步,但对集群的友好程度远高于散落几万个小文件。
上传大文件(超过单块大小,比如5GB)时,建议明确设置块大小与副本数。块大小通过-D dfs.blocksize=256M指定,也可以在写入后单独调整:
hdfs dfs -D dfs.blocksize=268435456 -put big.bin /data/块大小直接影响MapReduce的拆分粒度,如果后续要跑MR任务,128MB或256MB比较合适,太小会导致任务数过多,太大则并发度降低。
4. 目录创建、移动、复制与删除操作
4.1 创建目录:mkdir与touchz
创建目录用mkdir:
hdfs dfs -mkdir -p /user/data/interim/2025-p参数会递归创建所有不存在的父目录,这一点和Linux的mkdir -p一致。没有-p时,父目录不存在会直接报错。
touchz用于创建一个空文件:
hdfs dfs -touchz /user/data/flag如果文件已存在,touchz不会清空内容,但会更新修改时间;在Linux中touch也有类似行为。HDFS的touchz有一个特殊点:它不能创建目录下的零字节文件之外的内容,但可以用于生成占位文件、锁文件、或者某类任务结束的标记文件。我在调度系统里常用它来标记“某个环节已完成”,下游任务通过检查该文件是否存在来决定是否继续。
4.2 文件移动与重命名:mv
mv用于移动或重命名:
hdfs dfs -mv /data/old.txt /data/new.txt这个操作非常轻量,因为它只修改NameNode上的元数据,不移动实际块数据。即使文件有几十GB,mv也是瞬间完成。所以不要用cp来重命名文件,那会产生物理拷贝。
mv也支持跨目录移动:
hdfs dfs -mv /data/2025/part1.txt /archive/2025/需要注意,源和目标必须位于同一个HDFS集群内,HDFS不能直接跨集群mv,只能导出再导入。另外,mv不会改变文件副本数和块信息,它纯粹是元数据操作。
4.3 文件复制:cp
如果需要真正复制数据块,用cp:
hdfs dfs -cp /data/source /data/destcp会读取源文件并写入目标路径,实际操作中耗时与数据量成正比,而且会生成新的块副本。在同一个集群内复制大文件,cp相当于内部的数据搬移,耗费网络IO和磁盘IO。所以能用mv的时候不要用cp。
cp还有一些选项,比如-p保留权限、属主、时间戳等,但注意HDFS的cp -p在跨用户操作时可能因为权限不足报错。我在备份HDFS目录时常这样:
hdfs dfs -cp -p /user/hive/warehouse/db /backup/hive_202505104.4 删除文件:rm与延迟删除
删除用rm:
hdfs dfs -rm /data/unwanted.txt删除目录加-r:
hdfs dfs -rm -r /data/old_directory-skipTrash选项会让文件直接彻底删除,不进入回收站:
hdfs dfs -rm -skipTrash /data/urgent_delete.txt默认情况下,删除操作会先把文件移动到/user/<username>/.Trash/Current目录,这相当于一个软删除,可以在短时间内恢复。但注意,在HDFS中,文件从Trash清空或超过保留时间后,才是真正的块空间释放。如果你磁盘紧张,删除大量文件后建议观察Trash大小:
hdfs dfs -du -h /user/xx/.Trash/生产环境中误删文件是常有的事,依靠Trash恢复了好几次。所以尽量不要用-skipTrash,除非文件包含问题数据需要立刻清理。
删除大量文件时,建议分批删除,因为单次删除太多条目会给NameNode造成瞬时压力,导致RPC超时。一个折中方案是使用hdfs dfs -rm -r /目录/子目录按天删除,避免一锅端。
4.5 回收站与恢复误删数据
HDFS Trash的保留间隔由参数fs.trash.interval控制(单位分钟),默认可能是0,表示禁用。运维在配置集群时最好把它调成1440(1天)或以上。
如果真的误删了文件,可以这样恢复:
hdfs dfs -mv /user/xx/.Trash/Current/data/file.txt /data/file.txt注意,Trash目录路径包含删除时间和当前用户目录。如果文件是sbin用户删除的,你需要切到对应用户执行恢复,否则权限不足。
5. 权限、副本与空间管理命令
5.1 修改权限:chmod、chown
HDFS的权限模型与POSIX类似,但也有细微差别。基本命令格式和Linux一样:
hdfs dfs -chmod 750 /data/dir hdfs dfs -chown hive:hive /data/file.txt hdfs dfs -chgrp hadoop /data/file.txtHDFS ACL机制可以通过setfacl做到更细粒度的控制:
hdfs dfs -setfacl -m user:u1:r /data/file.txt查看ACL:
hdfs dfs -getfacl /data/file.txt在开启Kerberos的生产环境里,权限问题经常是Shell命令报错的元凶。以某个用户身份访问HDFS,如果hdfs dfs -ls能看但-put失败,先检查目标目录的写权限。曾经遇到一个奇怪案例:文件属主是hive,但hive用户明明有rwx权限,却无法删除该文件,排查后发现上层目录的写权限没开。HDFS删除文件需要同时具备该文件的删除权限和父目录的修改权限,这一点比Linux严格。
5.2 修改副本数:setrep
调副本数是最重要的运维操作之一。基础用法:
hdfs dfs -setrep -R 3 /data/important-R递归修改目录下所有文件的副本数,3是期望副本数。执行后输出会显示每个文件当前的副本数与最终结果。
副本数调大后,HDFS会异步在空闲DataNode上复制多余副本,不会立刻生效。调小时则会在后台删除多余副本。所以执行后立刻用ls查看,可能会看到副本数停留在旧值。等一段时间再验证,或者用:
hdfs fsck /data/important.file -files -blocks -locations查看具体块对应副本数。
经验是,临时目录、离线备份数据可以调到2甚至1,活跃生产数据保持3。调低副本数会导致集群可用空间增大,但可靠性下降。调整前务必确认数据的重要程度。
5.3 查看数据块分布与文件校验
除了fsck外,常用hdfs fsck /data/file.dat -files -blocks快速查看文件健康度:
-files:显示文件的基本块信息-blocks:显示每个块的ID和位置-locations:显示DataNode的具体位置
如果输出里有MISSING BLOCKS,说明某块有副本丢失,需要尽快追溯源数据重新备份。
5.4 配额管理:setQuota、clrQuota
管理员常常需要限制某个目录的文件数或空间。设置文件数限制:
hdfs dfsadmin -setQuota 1000 /user/proj_a设置空间限制(以字节为单位):
hdfs dfsadmin -setSpaceQuota 10g /user/proj_a查看配额:
hdfs dfs -count -q -h /user/proj_a这一组命令看似不属于“常用Shell”,但当你发现某个目录写不进数据时,十有八九是配额满了。先查配额,再查权限,效率最高。
6. 常见问题与排查技巧实录
6.1 Shell命令报“No such file or directory”
这个报错有多个可能:
- 路径写错,注意HDFS路径和本地路径的区别。
- 父目录不存在,缺少
-p参数创建父目录。 - 客户端类库与服务端版本不匹配,导致某些内部接口找不到。如果是后者,可升级客户端或核对版本。
先执行hdfs dfs -ls /确认根路径是否存在,再逐级ls定位哪一级开始异常。
6.2 “Permission denied”权限报错
权限问题最直接的处理:
hdfs dfs -ls -l /目标路径查看属主和权限,然后用chmod或chown调整。如果目标是目录且你只需要读子文件,需要掌握通行的目录权限。不要为了省事用-chmod 777,安全隐患很大。
6.3 “Safe mode is ON”拒绝写操作
集群刚启动或重启后,NameNode会进入安全模式一段时间。Shell里的写操作会失败,比如-put、-mkdir、-delete。查看状态:
hdfs dfsadmin -safemode get如果强制退出安全模式:
hdfs dfsadmin -safemode leave但生产环境建议等待安全模式自动退出,否则强行写入可能导致数据块尚未完全检查,风险偏高。
6.4 上传文件后副本数未达标
setrep -R 3执行后,用hdfs dfs -ls查看还是显示2?这是因为块复制是后台异步完成的,尤其在高负载集群里,可能需要几分钟到几小时。不要立刻断言失败,可以用hdfs dfsadmin -report观察Under-Replicated Blocks指标,如果它逐渐下降,说明正在复制。
如果长时间不变,检查DataNode磁盘空间和网络。常见原因是剩余空间不足,因为新副本会优先选择有空间且不在同一机架的节点。
6.5 磁盘容量显示与实际不一致
当df显示容量充足但写不进文件时,优先检查文件数配额和目录空间配额:
hdfs dfs -count -q -h /某目录配额会限制目录写操作,即使集群整体剩余空间很大。另一个可能是DataNode各磁盘利用率不均衡,导致某块盘写满,产生“No space available on datanode”的报错,而集群整体显示还有空间。这时需要开启磁盘均衡或手动迁移块隔离。
6.6 文件名含特殊字符导致脚本失效
用Shell脚本操作HDFS时,文件名可能包含(、&、空格等,容易出问题。解决办法用引号包裹:
hdfs dfs -put "file 1.txt" "/data/文件 (1).txt"更稳妥的做法是先列出文件路径,再逐行处理。注意HDFS Shell命令行对通配符*、?有一定的支持,但不要在路径里随意使用通配符,尤其是多个*时行为可能和你预期不同。
6.7 我常用的几个组合排查技巧
排查一个HDFS目录到底有什么问题时,我通常按这个顺序来:
hdfs dfs -ls -R -h /目录,看文件数量、大小、权限。hdfs fsck /目录 -files -blocks -locations,看块健康度。hdfs dfs -du -s -h /目录,看总占用。- 如果写入失败,看
hdfs dfsadmin -report确认集群状态。 - 最后检查项目空间的配额和目录权限。
这套流程基本覆盖 80% 的问题。
结尾
最后分享一个实际运维小经验:写HDFS Shell脚本时,一定不要忘了为每个命令加上set -e或者检查返回值,因为HDFS Shell偶尔会因为网络抖动返回非零码,而文件可能已经写入成功。如果不做幂等设计,后续重跑可能导致数据重复。我习惯在脚本里把hdfs dfs -put目标文件先-test -e判断一下,存在则先删除再上传,或者生成带时间戳的新文件。这样虽然多写两行代码,但能避免很多令人抓狂的脏数据问题。
另外一个冷门技巧:hdfs dfs -test -e <path>可以判断路径是否存在,配合-test -d、-test -f,比ls加grep高效得多。写自动化运维脚本时,这几个-test分支是真的香。
HDFS Shell命令看起来简单,但每个命令背后的元数据操作原理、权限模型、副本调度,才是真正决定你是否能把它用好的关键。希望这篇梳理能帮你少踩一些坑。