source csh脚本时无法访问已存在文件/目录的问题求助
问题排查:临时csh脚本无法访问已存在的日志文件
背景
用内嵌Python的csh脚本替代团队原有Perl脚本,执行流程为:用户带参数source .csh文件 → csh生成临时.py文件 → 执行临时.py并传入用户参数 → Python生成临时.csh文件 → 主csh脚本source该临时文件,目的是保留父shell(tcsh)的运行状态。
临时csh中执行grep检查日志文件时,出现「No such file or directory」错误,但日志文件确实存在,手动执行相同grep命令可正常运行,用ls查看目标目录也报同样错误。已尝试chmod授权临时csh文件、dos2unix转换所有临时文件,均无效。
关键代码与输出
主csh脚本核心片段
#!/usr/local/bin/tcsh set sourced=($_) if ("$sourced" != "") then if $sourced[1] == "source" then set script_dir = `pwd`/`dirname $sourced[2]` setenv DV_DIR "$script_dir/.." endif else set script_dir = `pwd`/`dirname $0` setenv DV_DIR "$script_dir/.." endif set prog_name = "run_v2" alias python /home/xxxxxxxx/pyinstall/python3 set temp_py_file = "$DV_DIR/scripts/temp_$prog_name.py" set command_file = "$DV_DIR/scripts/temp_$prog_name.csh" set temp_tcl_file = "$DV_DIR/scripts/temp_$prog_name.tcl" cat << EOF > $temp_py_file #!/home/xxxxxxxx/pyinstall/pyenv/shims python3 import os import sys import argparse def main(): <parser stuff> <script configuration> command_list = [ '#!/usr/local/bin tcsh', ] <misc stuff> if compile: cmd_extend_list = run_compile(config_dict, dv_dir, compile_dir, x_prop, coverage, local, config) command_list.extend(cmd_extend_list) command_file_path = os.path.join(dv_dir,'scripts','temp_run_v2.csh') with open(command_file_path, "w") as f: for command in command_list: f.write(f"{command}\n") return def run_compile(config_dict,dv_dir,compile_dir,x_prop,coverage,local,config): <building the compile_cmd using user inputs> if not os.path.exists(compile_dir): os.makedirs(compile_dir) command_list = [ f'printf "Info : Compile Directory = {compile_dir}' + r'\n\n"', f'printf "Info : Compile Command = {compile_cmd}' + r'\n\n"', f'printf "******* Starting Design and TB compile *******' + r'\n\n"', compile_cmd, f'printf "' + r'\n"', f'printf "******** Exiting Design and TB compile *******' + r'\n\n"', ] cmd_extend_list = check_result(log_path) command_list.extend(cmd_extend_list) return command_list def check_result(log_path): command_list = [ f'set errors_found=\`grep "\*E" "{log_path}"\`', f'if ("\$#errors_found" != 0) then', f' printf "Info : Compilation failed.' + r'\n"', f' printf "Error : Check the compile log for errors - {log_path}' + r'\n\n"', f' exit 1', f'else', f' printf "Info : Compilation successful.' + r'\n\n"', f'endif', '' ] return command_list if __name__ == "__main__": main() EOF dos2unix $temp_py_file python $temp_py_file $argv set py_status = $status if ($py_status != 0) then printf "\nError : $prog_name exited with the error code $py_status.\n\n" exit 1 endif rm -f $temp_py_file if ( -e $command_file ) then dos2unix $command_file chmod 777 $command_file source $command_file set prog_name = "run_v2" set command_file = "$DV_DIR/scripts/temp_$prog_name.csh" rm -f $command_file else printf "\nError: Command file $command_file was not created. Check Python script for issues.\n\n" endif if ( -e $temp_tcl_file ) then set temp_tcl_file = "$DV_DIR/scripts/temp_$prog_name.tcl" rm -f $temp_tcl_file endif
生成的临时csh文件
#!/usr/local/bin tcsh printf "Info : Compile Directory = <compile_dir>" printf "Info : Compile Command = <compile_cmd ... -l <log path>>" printf "******* Starting Design and TB compile *******\n\n" <compile_cmd> printf "\n" printf "******** Exiting Design and TB compile *******\n\n" set errors_found=`grep "\*E" "<log path>"` if ("$#errors_found" != 0) then printf "Info : Compilation failed.\n" printf "Error : Check the compile log for errors - <log path>\n\n" exit 1 else printf "Info : Compilation successful.\n\n" endif
报错输出
TOOL: xrun(64) 22.09-s006: Started on Nov 02, 2024 at 15:55:31 IST xrun: *E,FILEMIS: Cannot find the provided file /xxxx/xxxx/xxxx. TOOL: xrun(64) 22.09-s006: Exiting on Nov 02, 2024 at 15:55:32 IST (total: 00:00:01) ******** Exiting Design and TB compile ******* grep: <log path>: No such file or directory Info : Compilation successful.
手动执行grep结果
grep "\*E" "<log path>" xrun: *E,FILEMIS: Cannot find the provided file /xxxx/xxxx/xxxx.
排查分析
- 路径转义缺失:
log_path可能包含空格、$、()等csh特殊字符,Python生成csh命令时未对这些字符转义,导致csh解析路径时出现错误。 - 工作目录不一致:主csh的工作目录与临时csh执行时的工作目录不符,若
log_path是相对路径,会导致临时csh找不到目标文件。 - 变量展开错误:若
log_path包含csh环境变量(如$DV_DIR),Python生成临时csh时未将变量展开为实际路径,而临时csh执行时该变量未正确定义或展开。 - 进程上下文差异:临时csh执行时的进程上下文(如用户权限、环境变量)与手动执行时不同,但手动执行正常的话此可能性较低。
解决方案
方案1:绝对路径+特殊字符转义
在Python的check_result函数中,先将log_path转为绝对路径,再对csh特殊字符进行转义:
def escape_csh_path(path): # 转义csh中需特殊处理的字符 special_chars = [' ', '$', '(', ')', '*', '?', '[', ']', ';', '&', '|', '<', '>'] for char in special_chars: path = path.replace(char, f'\\{char}') return path def check_result(log_path): # 转为绝对路径并转义 escaped_log_path = escape_csh_path(os.path.abspath(log_path)) command_list = [ f'set errors_found=`grep "\\*E" "{escaped_log_path}"`', f'if ("\$#errors_found" != 0) then', f' printf "Info : Compilation failed.' + r'\n"', f' printf "Error : Check the compile log for errors - {escaped_log_path}' + r'\n\n"', f' exit 1', f'else', f' printf "Info : Compilation successful.' + r'\n\n"', f'endif', '' ] return command_list
方案2:强制临时csh切换到目标工作目录
在Python的run_compile函数生成的command_list开头,添加切换到compile_dir的命令,确保相对路径生效:
def run_compile(config_dict,dv_dir,compile_dir,x_prop,coverage,local,config): # ... 原有代码 escaped_compile_dir = escape_csh_path(os.path.abspath(compile_dir)) command_list = [ f'cd "{escaped_compile_dir}"', f'printf "Info : Compile Directory = {compile_dir}' + r'\n\n"', f'printf "Info : Compile Command = {compile_cmd}' + r'\n\n"', # ... 其余原有命令 ] # ... 原有代码
方案3:确保变量提前展开
如果log_path是基于csh环境变量生成的,在Python中直接获取变量的实际值拼接路径,而非保留变量名。例如:
dv_dir = os.environ.get("DV_DIR", "") log_path = os.path.join(dv_dir, "path", "to", "logfile.log")
方案4:添加调试命令定位问题
在生成的临时csh开头添加调试命令,查看执行环境:
printf "Debug: Current working directory = %s\n" `pwd` printf "Debug: DV_DIR = %s\n" $DV_DIR ls -la "<log path>"
执行后根据输出确认工作目录、环境变量与路径是否匹配。
内容的提问来源于stack exchange,提问作者Rishi




