Unix Shell脚本中如何将Hadoop命令执行结果赋值给变量
代码问题排查与修正说明
你用反引号包裹Hadoop命令给变量赋值的写法本身语法合法,运行报错是上下文逻辑错误导致的,具体问题点和修复方案如下:
存在的核心问题
- 冗余无效的cat命令:脚本第一行
cat ${AI_SERIAL_LOOKUP}/${BBCA_HDFS_Config_File}没有实际作用,后续while循环已经通过输入重定向读取同一个文件,这行只会额外输出一次文件全量内容,浪费IO资源。 - 变量名冲突:外层while循环读取配置文件行的变量名为
line,内层管道后的while循环也使用line作为读取变量,会直接覆盖外层存储HDFS路径的变量值,导致后续路径解析错乱。 - 管道子shell陷阱:
hdfs dfs -ls ${hdfs_path} | while read line的写法中,管道右侧的while循环运行在独立子shell中,循环内部赋值的hdfs_create_datetime变量在循环结束后会直接销毁,父shell完全无法读取到该值。 - HDFS命令输出解析错误:
hdfs dfs -ls的输出第一行是文件总数统计(格式类似Found N items),且每一行的完整内容包含权限、副本数、属主、文件大小、修改时间、路径共6段内容,直接把整行内容作为路径传给hadoop fs -stat必然触发参数非法报错。 - 变量未加引号包裹:所有引用
${hdfs_path}、${line}的位置都没有加双引号,一旦路径包含空格、特殊字符就会触发参数拆分错误。 - 返回值判断不可靠:单独执行
hdfs dfs -ls后再通过$?判断执行结果的写法,很容易因为中间插入的echo等命令覆盖$?的取值,导致判断逻辑失效。
排查步骤
- 前置环境校验:先手动执行
echo "${AI_SERIAL_LOOKUP}/${BBCA_HDFS_Config_File}"确认配置文件路径存在,再单独执行hdfs dfs -ls 配置文件内的任意一条测试路径,确认当前执行用户有HDFS访问权限、无Kerberos认证拦截、Hadoop客户端环境变量配置正确。 - 变量冲突修复:把内层循环的读取变量重命名为和外层不冲突的名称,比如
hdfs_file_entry。 - 跳过无效输出行:过滤
hdfs dfs -ls输出的第一行统计信息,同时提取每行的最后一列(即真实HDFS文件路径)再传给stat命令。 - 规避子shell问题:如果需要在内层循环外使用
hdfs_create_datetime变量,不要用管道写法,改用进程替换或者先把ls结果写入临时文件再读取,避免子shell变量隔离问题。
修正后参考代码
# 移除开头冗余的cat命令,read加-r参数避免反斜杠转义问题 while read -r hdfs_path do # 跳过配置文件里的空行、注释行 [ -z "${hdfs_path}" ] && [[ "${hdfs_path}" =~ ^# ]] && continue echo "Processing path: ${hdfs_path}" # 直接把hdfs命令作为if判断条件,避免$?取值被干扰,无关输出丢入空设备 if hdfs dfs -ls "${hdfs_path}" >/dev/null 2>&1 then write_log "hdfs directory exist" # 用进程替换替代管道,规避子shell变量隔离问题;tail -n +2跳过第一行统计信息 while read -r hdfs_file_entry do # 提取ls输出最后一列的真实文件路径 real_file_path=$(echo "${hdfs_file_entry}" | awk '{print $NF}') [ -z "${real_file_path}" ] && continue echo "Processing file: ${real_file_path}" # 推荐用$()替代反引号做命令赋值,嵌套可读性更强,所有变量加双引号包裹 hdfs_create_datetime=$(hadoop fs -stat "%y" "${real_file_path}") # 此处可直接使用hdfs_create_datetime变量,无子shell隔离问题 echo "File create time: ${hdfs_create_datetime}" done < <(hdfs dfs -ls "${hdfs_path}" | tail -n +2) else write_log "hdfs directory does not exist. Please check." fi done < "${AI_SERIAL_LOOKUP}/${BBCA_HDFS_Config_File}"
如果运行环境使用dash等不支持进程替换的轻量shell,可以先把
hdfs dfs -ls的结果写入临时文件,内层循环读取临时文件的方式实现相同逻辑,规避子shell问题。
内容的提问来源于stack exchange,提问作者Priscilla Samuel
相关产品推荐
相关产品推荐

