You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

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.

排查分析

  1. 路径转义缺失log_path可能包含空格、$()等csh特殊字符,Python生成csh命令时未对这些字符转义,导致csh解析路径时出现错误。
  2. 工作目录不一致:主csh的工作目录与临时csh执行时的工作目录不符,若log_path是相对路径,会导致临时csh找不到目标文件。
  3. 变量展开错误:若log_path包含csh环境变量(如$DV_DIR),Python生成临时csh时未将变量展开为实际路径,而临时csh执行时该变量未正确定义或展开。
  4. 进程上下文差异:临时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

火山引擎 最新活动