/export/yhdfs/daily_check_new/yhdfs/script/../scri...
تم الإنشاء في: ٢٥ نوفمبر ٢٠٢٥
تم الإنشاء في: ٢٥ نوفمبر ٢٠٢٥
/export/yhdfs/daily_check_new/yhdfs/script/../script/modules/check_trash.sh: line 115: sh /export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh -trash_hadoop_home /export/jcloud-hadoop/hadoop-2.6.1-trash_client -trash_ips 10.226.193.236,10.226.194.41 -max_trash_memory 2 -local_log_dir /export/yhdfs/daily_check_new/yhdfs/script/../log/2025-11-25/13:03:04/pre_bdp/trash_check -trash_expire_minutes 1560: No such file or directory
分析一下 这个错误
下面对你提供的报错做一个系统性的分析,并给出排查思路。
报错信息如下:
text/export/yhdfs/daily_check_new/yhdfs/script/../script/modules/check_trash.sh: line 115: sh /export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh -trash_hadoop_home /export/jcloud-hadoop/hadoop-2.6.1-trash_client -trash_ips 10.226.193.236,10.226.194.41 -max_trash_memory 2 -local_log_dir /export/yhdfs/daily_check_new/yhdfs/script/../log/2025-11-25/13:03:04/pre_bdp/trash_check -trash_expire_minutes 1560: No such file or directory
核心问题:shell 在执行 sh <command> 时,认为文件不存在。
即报错来自这段执行命令,而非脚本本身的语法错误。
: 导致被当成“文件名”,从而报错(最常见)你有个参数路径:
/export/yhdfs/.../log/2025-11-25/13:03:04/pre_bdp/trash_check
其中 13:03:04 包含 冒号 :。
Linux 对命令行没问题,但:
[ -d "$path" ],路径中冒号可能导致判断失败因此,脚本调用时认为路径不存在,返回“No such file or directory”。
trash_check_cluster.sh 这个文件本身不存在或没执行权限请检查:
ls -l /export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh
需要满足:
chmod +x但通常这个组件不会突然消失,因此概率较低。
特别是脚本自动创建的日志目录:
/export/yhdfs/daily_check_new/yhdfs/script/../log/2025-11-25/13:03:04/pre_bdp/trash_check
可能没有被 mkdir -p 正确创建。
可以测试:
ls /export/yhdfs/daily_check_new/yhdfs/log/2025-11-25/
如果没有 13:03:04 ,则内部 mkdir 失败导致脚本报错。
例如脚本里:
sh <path> -params...
如果换行里有 \r,shell 可能找不到 <path>\r 这个文件 → 报同样错误。
但这种情况一般只发生在手工编辑的脚本,自动任务较少出现。
:Linux 允许目录名含 :,但在脚本中很容易造成误判 / 变量解析错误。
建议更改日志目录命名方式,例如:
把:
13:03:04
改成:
13_03_04
或:
13-03-04
你可以修改生成目录的脚本部分,从:
$(date +%H:%M:%S)
改为:
$(date +%H_%M_%S)
或
$(date +%H-%M-%S)
你可以手动执行命令:
textsh /export/.../trash_check_cluster.sh \ -local_log_dir /export/.../log/2025-11-25/13:03:04/pre_bdp/trash_check
如果报错依旧,把路径改成不含冒号版本,再试:
textmkdir -p /tmp/log_test/13_03_04 sh ... -local_log_dir /tmp/log_test/13_03_04
如果这个能正常执行,100% 是冒号引起的问题。
你的报错 几乎可以确定 是由日志目录路径包含
13:03:04的冒号导致脚本无法正确解析路径,从而 shell 报:
No such file or directory
如果你愿意,我也可以:
✅ 帮你排查原脚本第 115 行
✅ 帮你修改日志目录生成方式
✅ 帮你确认是否存在其他路径冲突
只要你贴出脚本对应部分即可。
要继续分析吗?
那能不能加个引号? 让路径可以被正确识别?
可以加引号,但未必能完全解决问题 —— 具体取决于脚本内部有没有进一步对路径做处理。
下面把情况讲清楚:
如果你在调用脚本时这样写:
bashsh /export/.../trash_check_cluster.sh \ -local_log_dir "/export/.../log/2025-11-25/13:03:04/pre_bdp/trash_check"
👉 shell 本身会正确把路径当成一个整体参数,不会把冒号切开。
因此,如果错误来自 外层调用阶段,加引号就能修复。
即使外面加了引号,但如果脚本内部:
dirname / basename 解析路径这两个命令对包含 : 的路径结果不可控,尤其是:
bashdirname /path/13:03:04/log
部分系统会异常输出,导致目录创建失败。
awk, sed, tr 做路径字符串处理例如:
bashecho $local_log_dir | awk -F ':' '{print $1}'
会直接被冒号切开!!!
Java 部分库会把 : 当成 classpath 分隔符。
Hadoop 处理路径时也可能不接受一些特殊字符。
例如:
bashlogdir=$base/$time/pre_bdp mkdir -p $logdir # 如果没有双引号,冒号仍会被误解
如果脚本内部对路径做处理,冒号仍可能导致未知错误。
Linux 允许,但并不推荐。
如果你的日志目录是由 date +%H:%M:%S 生成,建议改为:
date +%H_%M_%S
或
date +%H-%M-%S
如果你能修改脚本,确保:
bashmkdir -p "$local_log_dir"
并且所有涉及路径的地方都使用双引号:
bashcp "$src" "$local_log_dir" cd "$local_log_dir" echo "$local_log_dir"
这样即便有冒号,也不会出问题。
只要你把脚本里相关段落(尤其是第 115 行和 trash_check_cluster.sh 内部相关部分)贴出来即可。
trash_cmd="{TRASH_LOCAL_LOG_DIR}"
怎么给他加 引号?
你可以在 变量赋值阶段 或 最终执行阶段给参数加引号。下面给你明确、安全、可运行的写法。
bashtrash_cmd="$trash_cmd -local_log_dir ${TRASH_LOCAL_LOG_DIR}"
如果 ${TRASH_LOCAL_LOG_DIR} 含有 : 或空格,这样写会导致路径被拆开。
bashtrash_cmd="$trash_cmd -local_log_dir \"$TRASH_LOCAL_LOG_DIR\""
这样 trash_cmd 里会变成:
-local_log_dir "/export/.../13:03:04/pre_bdp/trash_check"
✔ 在最终执行时路径仍然是一个整体
✔ 冒号不会被误解
✔ 对后续脚本最安全
如果你最终执行命令是:
bashsh $trash_cmd
你可以检查 echo:
bashecho "$trash_cmd"
输出应该是这样:
... -local_log_dir "/export/.../13:03:04/pre_bdp/trash_check"
✔ 引号已经嵌入到命令里了。
例如:
bashtrash_cmd="$trash_cmd -local_log_dir ${TRASH_LOCAL_LOG_DIR}"
改成:
bashtrash_cmd="$trash_cmd -local_log_dir \"${TRASH_LOCAL_LOG_DIR}\""
和方式 1 的效果一样,但变量扩展更繁琐。
bashtrash_cmd="$trash_cmd -local_log_dir "${TRASH_LOCAL_LOG_DIR}""
外层和内层引号会冲突,语法错误。
也不要写:
bashtrash_cmd="$trash_cmd -local_log_dir ${TRASH_LOCAL_LOG_DIR}"
并希望 sh $trash_cmd 自己处理。
bashtrash_cmd="$trash_cmd -local_log_dir \"$TRASH_LOCAL_LOG_DIR\""
单引号行吗? 我手动执行是可以的 双引号好像不行
单引号当然可以用,但关键不在“单引号还是双引号”,而在于你后面是怎么执行 trash_cmd 的。
你现在这种“拼命令字符串”的方式里:
' 或 ",脚本当然找不到目录,于是报 No such file or directory。这也解释了你说的:手动执行可以,但脚本里双引号不行。
拼接时这样写(外层双引号用于展开变量,里面用单引号包路径):
bashtrash_cmd="$trash_cmd -local_log_dir '$TRASH_LOCAL_LOG_DIR'"
执行时必须用 eval:
basheval "sh $trash_cmd"
这样单引号会在 eval 时被重新当成语法解释掉,路径就不会带引号了。
⚠️ 但
eval有风险(万一变量里有奇怪字符会被当命令执行),不太推荐长期用。
bashtrash_cmd=(sh /export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh) trash_cmd+=(-trash_hadoop_home "$TRASH_HADOOP_HOME") trash_cmd+=(-trash_ips "$TRASH_IPS") trash_cmd+=(-max_trash_memory "$MAX_TRASH_MEMORY") trash_cmd+=(-local_log_dir "$TRASH_LOCAL_LOG_DIR") trash_cmd+=(-trash_expire_minutes "$TRASH_EXPIRE_MINUTES") "${trash_cmd[@]}"
数组方式的好处:
你大概率是这样执行的:
bashsh $trash_cmd
这会导致 "$TRASH_LOCAL_LOG_DIR" 里的引号变成普通字符传给脚本,路径实际变成:
"/export/.../13:03:04/..."
带着 " 去找目录 → 当然找不到。
bashtrash_cmd="$trash_cmd -local_log_dir '$TRASH_LOCAL_LOG_DIR'" eval "sh $trash_cmd"
如果你把 trash_cmd 最后是怎么执行的那一段贴出来,我可以直接按你的现场结构给你改成最小改动且稳定的版本。
TRASH_SCRIPT_PATH="/export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh"
TRASH_LOCAL_LOG_DIR="LOG_DIR/trash_check"
# 构建垃圾回收检查命令
local trash_cmd="sh TRASH_SCRIPT_PATH"
text# 添加参数(如果配置了的话) if [[ -n "$TRASH_HADOOP_HOME" ]]; then trash_cmd="$trash_cmd -trash_hadoop_home $TRASH_HADOOP_HOME" fi if [[ -n "$TRASH_IPS" ]]; then trash_cmd="$trash_cmd -trash_ips $TRASH_IPS" fi if [[ -n "$TRASH_MAX_MEMORY" ]]; then trash_cmd="$trash_cmd -max_trash_memory $TRASH_MAX_MEMORY" fi if [[ -n "$TRASH_LOCAL_LOG_DIR" ]]; then trash_cmd="$trash_cmd -local_log_dir \"$TRASH_LOCAL_LOG_DIR\"" fi if [[ -n "$TRASH_EXPIRE_MINUTES" ]]; then trash_cmd="$trash_cmd -trash_expire_minutes $TRASH_EXPIRE_MINUTES" fi if [[ -n "$TRASH_YHDFS_VERSION" ]]; then trash_cmd="$trash_cmd -trash_yhdfs_version $TRASH_YHDFS_VERSION" fi if [[ -n "$TRASH_METRIC_COUNT_DELETE" ]]; then trash_cmd="$trash_cmd -count_delete $TRASH_METRIC_COUNT_DELETE" fi log_info "执行垃圾回收检查命令: \"$trash_cmd\"" # 设置输出文件路径 - 统一存储到RECORD_DIR local output_file="$RECORD_DIR/trash_check_collection_stat.txt" # 执行垃圾回收检查并保存结果 "$trash_cmd" > "$output_file" 2>&1
我是这么执行的
啊,这下问题就清晰了,你这段代码的问题核心不在引号里有没有冒号,而是在最后那一句怎么执行命令。
先看关键几行(我稍微缩进下):
bashTRASH_SCRIPT_PATH="/export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh" TRASH_LOCAL_LOG_DIR="$LOG_DIR/trash_check" local trash_cmd="sh $TRASH_SCRIPT_PATH" # 一路拼字符串…… trash_cmd="$trash_cmd -trash_hadoop_home $TRASH_HADOOP_HOME" ... trash_cmd="$trash_cmd -local_log_dir \"$TRASH_LOCAL_LOG_DIR\"" ... log_info "执行垃圾回收检查命令: \"$trash_cmd\"" local output_file="$RECORD_DIR/trash_check_collection_stat.txt" # 真正执行 "$trash_cmd" > "$output_file" 2>&1
"$trash_cmd" 这一句这一句:
bash"$trash_cmd" > "$output_file" 2>&1
对 shell 来说的含义是:
把整个变量内容当成一个命令名来执行。
也就是说,shell 会尝试执行一个叫做:
textsh /export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh -local_log_dir "/export/..."
的文件 😅
当然找不到这个文件,所以才报:
textNo such file or directory
和里面的参数、路径、冒号已经没关系了,是整条命令被当成了“程序名”。
你可以先把 -local_log_dir 那行先改回最简单的(它其实不需要引号,路径里没有空格就没问题):
bashif [[ -n "$TRASH_LOCAL_LOG_DIR" ]]; then trash_cmd="$trash_cmd -local_log_dir $TRASH_LOCAL_LOG_DIR" fi
然后最重要的是,把执行那一行改成:
bash# 不要加双引号,让 shell 正常做词法拆分 $trash_cmd > "$output_file" 2>&1
这样:
$trash_cmd 会被 shell 拆成:sh TRASH_SCRIPT_PATH -local_log_dir /路径/...sh 会去执行脚本,后面的参数都会正常传进去⚠️ 注意:此时你在上面拼的
\"...\"这种不会当成“语法引号”,只会变成普通字符"path",所以那种写法确实是不对的。
如果你愿意稍微改得规范一点,可以直接用 数组 构命令(以后加参数也不容易出错):
bashTRASH_SCRIPT_PATH="/export/yhdfs/daily_check_new/yhdfs/script/modules/trash_check_cluster.sh" TRASH_LOCAL_LOG_DIR="$LOG_DIR/trash_check" # 用数组来存命令和参数 local trash_cmd=(sh "$TRASH_SCRIPT_PATH") if [[ -n "$TRASH_HADOOP_HOME" ]]; then trash_cmd+=(-trash_hadoop_home "$TRASH_HADOOP_HOME") fi if [[ -n "$TRASH_IPS" ]]; then trash_cmd+=(-trash_ips "$TRASH_IPS") fi if [[ -n "$TRASH_MAX_MEMORY" ]]; then trash_cmd+=(-max_trash_memory "$TRASH_MAX_MEMORY") fi if [[ -n "$TRASH_LOCAL_LOG_DIR" ]]; then trash_cmd+=(-local_log_dir "$TRASH_LOCAL_LOG_DIR") fi if [[ -n "$TRASH_EXPIRE_MINUTES" ]]; then trash_cmd+=(-trash_expire_minutes "$TRASH_EXPIRE_MINUTES") fi if [[ -n "$TRASH_YHDFS_VERSION" ]]; then trash_cmd+=(-trash_yhdfs_version "$TRASH_YHDFS_VERSION") fi if [[ -n "$TRASH_METRIC_COUNT_DELETE" ]]; then trash_cmd+=(-count_delete "$TRASH_METRIC_COUNT_DELETE") fi log_info "执行垃圾回收检查命令: \"${trash_cmd[*]}\"" local output_file="$RECORD_DIR/trash_check_collection_stat.txt" # 数组执行,参数自动按元素拆分 "${trash_cmd[@]}" > "$output_file" 2>&1
优点:
${trash_cmd[*]} 还能打印出完整命令看着也方便'路径' 还是 "路径","$trash_cmd" 这样执行,你可以先试试只把最后一行改成 $trash_cmd 看是否不再报 “No such file or directory”;如果还是有问题,把新的报错贴出来,我帮你继续往下捋。