求助:Shell脚本遍历HDFS目录及获取文件创建时间失败问题
解决HDFS目录遍历与文件时间筛选的问题
你遇到的问题主要来自两个核心点:HDFS的ls输出格式和本地Linux完全不同,以及操作HDFS文件需要用专门的Hadoop命令而非本地命令,我来一步步帮你修正脚本:
为什么原来的遍历写法失效?
本地ls /path/*会直接输出每个文件的路径,但HDFS的hadoop fs -ls /TestDir输出是这样的格式:
Found 2 items -rw-r--r-- 3 user hadoop 123 2024-05-20 10:30 /TestDir/file1.txt -rw-r--r-- 3 user hadoop 456 2024-05-21 14:15 /TestDir/file2.txt
当你用for i in hadoop fs -ls /TestDir``时,shell会把所有空格分割的内容都当成循环项——比如-rw-r--r--、3、user、/TestDir/file1.txt都会被单独赋值给i,这显然不是你要的文件路径。
修正后的完整脚本
推荐用hadoop fs -find来遍历HDFS文件(更可靠,支持递归/非递归,还能处理带空格的文件名),同时替换本地命令为HDFS专用命令:
#!/bin/bash # 配置路径 HDFS_SOURCE_DIR="/TestDir" LOCAL_OUTPUT_DIR="/home/user/OutputDir" # 遍历HDFS目录下的所有文件(-type f 表示只找文件,排除目录;如果要递归子目录去掉-maxdepth 1) hadoop fs -find "$HDFS_SOURCE_DIR" -maxdepth 1 -type f | while read -r file_path; do echo "正在处理文件: $file_path" # 获取HDFS文件的时间(这里用%y取最后修改时间,若需创建时间请看下文注意事项) file_time=$(hadoop fs -stat %y "$file_path") # 提取日期部分(格式:YYYY-MM-DD) file_date=$(echo "$file_time" | cut -c 1-10) echo "文件日期: $file_date" # 和当前日期对比 if [ "$file_date" = "$(date +%F)" ]; then # 从HDFS复制到本地(用copyToLocal或get命令,不能用本地cp) hadoop fs -copyToLocal "$file_path" "$LOCAL_OUTPUT_DIR/" echo "✅ 已成功复制 $file_path 到 $LOCAL_OUTPUT_DIR" fi done
关键细节说明
遍历方式的选择
- 如果不需要递归子目录,加
-maxdepth 1参数;如果要递归遍历所有子目录,去掉这个参数即可。 - 用
while read -r替代for循环:如果文件名包含空格,for会按空格分割路径,而while read会按行读取,避免错误。
- 如果不需要递归子目录,加
HDFS文件时间的获取
HDFS的stat命令参数和本地略有差异,你可以用hadoop fs -stat --help查看你当前版本支持的选项:%y:文件最后修改时间(人类可读格式,如2024-05-20 10:30:00)%Y:最后修改时间的毫秒时间戳- 部分Hadoop版本支持
%b获取文件创建时间(birth time),如果你的需求是创建时间,把%y换成%b即可。
HDFS文件操作命令
本地的cp、stat等命令无法直接操作HDFS文件,必须用Hadoop提供的命令:- 复制HDFS文件到本地:
hadoop fs -copyToLocal或hdfs dfs -get - 获取HDFS文件属性:
hadoop fs -stat - 查看HDFS目录:
hadoop fs -ls
- 复制HDFS文件到本地:
备用方案(不用find,用ls处理)
如果你坚持用ls,需要过滤掉无用行并提取文件路径:
#!/bin/bash HDFS_SOURCE_DIR="/TestDir" LOCAL_OUTPUT_DIR="/home/user/OutputDir" # 过滤掉ls开头的"Found X items"行,然后提取第8个字段(文件路径) for file_path in $(hadoop fs -ls "$HDFS_SOURCE_DIR" | grep -v "^Found" | awk '{print $8}'); do # 后续逻辑和上面的脚本一致 echo "正在处理文件: $file_path" # ... 省略时间获取和复制逻辑 done
⚠️ 注意:这种方式不支持带空格的文件名,优先推荐find+while read的写法。
内容的提问来源于stack exchange,提问作者Rj1
相关产品推荐
相关产品推荐

