Bash 脚本无法识别现有文件

Bash script not recognizing existing file

我必须编写一个简单的 bash 脚本,它会编译多个 sql 脚本,这些脚本可以包含对其他 sql 脚本的递归引用 Oracle SQLPlus convention , 所以最终结果将只有一个 SQL 文件,包含来自所有(可能也递归地)引用的下标的所有语句。

我使用以下 bash 代码创建了一个名为 oracle-script-compressor.sh 的简单脚本:

#!/bin/bash
#
#
function err () {
    echo $* > "/dev/stderr"
}


function replace_subscripts_placeholders() {
    local PROCESSING_FILENAME=
    echo "-- processing file $PROCESSING_FILENAME"
    while read script_line; do
        local script_line_NO_LEAD_SPACE="$(echo -e "${script_line}" | sed -e 's/^[[:space:]]*//')"
        if  [[ $script_line_NO_LEAD_SPACE == \@\@* ]] ; then
            local file_name="./${script_line_NO_LEAD_SPACE#\@\@}"
            echo "-- found reference to file $file_name"
            echo "-- starting with processing, pwd=$PWD"
            # for debug purposes:
            ls -la
            # but this returns always false:
            if [ -f "$file_name" ]; then
                # so this part is never started:
                . replace_subscripts_placeholders $file_name
            else
                err_msg="WARNING: Could not find the referenced file $file_name"
                echo "-- $err_msg"
                err $err_msg
            fi          
        else
            echo "$script_line"
        fi
    done < $PROCESSING_FILENAME 
}

if test -z "" ; then
    err "Usage: oracle-script-compressor.sh {file_name_to_process} [> output_file]"
    err "  Be aware, if the referenced files within {file_name_to_process} are not specified by absolute paths, you have to start the script from corresponding directory."
    err "  If the part [> output_file] is omitted, then this script writes to standard output"
    err "  If the part [>> output_file] is used, then the result will be appended to output_file it it exists before the processing"
else
    if [ -f "" ]; then
        replace_subscripts_placeholders 
    else
        echo "file  does not exist"
    fi
fi

并且我陷入了一个有趣的问题 - 似乎在函数 replace_subscripts_placeholders() 内部文件检查

        if [ -f "$file_name" ]; then
            . replace_subscripts_placeholders $file_name
        else
            err_msg="WARNING: Could not find the referenced file $file_name"
            echo "-- $err_msg"
            err $err_msg
        fi          

永远不会进行递归调用,即使我删除了 if 语句并真正使用正确的引用文件名递归调用函数,它仍然存在,但仍然无法识别并没有传递到在递归调用中循环遍历引用文件的所有行(然后出现找不到文件的错误,无法执行循环)。

我已经将调试消息添加到脚本中,就像上面提到的那样,但我仍然找不到,为什么 bash 找不到文件,如果它在同一个目录中。脚本放在

user@mycomputer:/tmp/test$ ls -la
celkem 52
drwxr-xr-x  2 user user  4096 zář 14 21:47 .
drwxrwxrwt 38 root     root     36864 zář 14 21:48 ..
-rw-r--r--  1 user user    51 zář 14 21:45 a.sql
-rw-r--r--  1 user user    51 zář 14 21:45 b.sql
-rw-r--r--  1 user user   590 zář 14 21:46 start.sql
user@mycomputer:/tmp/test$ 

文件内容 start.sql 如下所示:

spool output__UpdSch.log
whenever sqlerror exit sql.sqlcode 
--
--
PROMPT a.sql - starting
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as START_TIMESTAMP from dual;
@@a.sql
PROMPT a.sql - finished
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as FINISH_TIMESTAMP from dual;
--
--
PROMPT b.sql - starting
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as START_TIMESTAMP from dual;
@@b.sql
PROMPT b.sql - finished
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as FINISH_TIMESTAMP from dual;
--
--
spool off

如果我执行脚本,它似乎正确地解码了文件名,但是 bash 中仍然存在问题 - 文件存在性测试 returns 总是错误的:

user@mycomputer:/tmp/test$ ~/tmp/oracle-script-compressor.sh start.sql 
-- processing file start.sql
spool output__UpdSch.log
whenever sqlerror exit sql.sqlcode 
--
--
PROMPT a.sql - starting
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as START_TIMESTAMP from dual;
-- found reference to file ./a.sql
-- starting with processing, pwd=/tmp/test
celkem 52
drwxr-xr-x  2 user user  4096 zář 14 21:47 .
drwxrwxrwt 38 root     root     36864 zář 14 21:48 ..
-rw-r--r--  1 user user    51 zář 14 21:45 a.sql
-rw-r--r--  1 user user    51 zář 14 21:45 b.sql
-rw-r--r--  1 user user   590 zář 14 21:46 start.sql
-- WARNING: Could not find the referenced file ./a.sql
WARNING: Could not find the referenced file ./a.sql
PROMPT a.sql - finished
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as FINISH_TIMESTAMP from dual;
--
--
PROMPT b.sql - starting
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as START_TIMESTAMP from dual;
-- found reference to file ./b.sql
-- starting with processing, pwd=/tmp/test
celkem 52
drwxr-xr-x  2 user user  4096 zář 14 21:47 .
drwxrwxrwt 38 root     root     36864 zář 14 21:48 ..
-rw-r--r--  1 user user    51 zář 14 21:45 a.sql
-rw-r--r--  1 user user    51 zář 14 21:45 b.sql
-rw-r--r--  1 user user   590 zář 14 21:46 start.sql
-- WARNING: Could not find the referenced file ./b.sql
WARNING: Could not find the referenced file ./b.sql
PROMPT b.sql - finished
select to_char(current_timestamp,'YYYY-MM-DD HH24:MI:SS.FF3') as FINISH_TIMESTAMP from dual;
--
--
spool off
user@mycomputer:/tmp/test$ 

脚本对文件有读取权限,所有东西都在我启动脚本的同一个文件夹中,也没关系,如果我引用当前目录前缀为“./”的文件,它只是从未被发现。有趣的是,脚本启动期间的检查正确通过,唯一的问题是函数内的搜索......我也尝试过调用带有前缀“。”的函数。没有它,它没有区别......引用的文件名中也没有尾随空格......如果我将函数内部的变量声明为本地变量也没有区别。 所以我不知道,可能是什么问题,也许我只是看得太久而看不到一些东西 - 似乎它必须是微不足道的东西,比如函数是在某个不同的当前目录中启动的 - (但 pwd 和 ls 显示目录总是正确的...???) - 任何帮助或指示将不胜感激。

感谢您的评论,它让我找到了解决方案。我发现,这个问题与事实有关,测试 sql 文件是在 Windows 上创建的,所以它们在行尾总是有 <CR><LF> 个字符。这导致了我发布的原始 bash 脚本中的事实,即脚本行

while read script_line

不仅将行中的给定文件名放入变量中,而且前面加上字符@@

@@a.sql

还有 <CR> 字符 - 变量中的值就是

@@a.sql<CR>

什么原因导致文件 a.sql 等永远找不到。当然这个字符是不可见的,所以它没有在我在这里进行的任何调试回显中显示 - 我不得不将 $file_name 的内容放在其他一些字符之间,然后我可以在回显测试中看到它.. . 我还做了一些其他的更正,最终的工作脚本如下所示,如果有人需要将引用的 SQL 脚本合并为一个,这样做:

#!/bin/bash
#
#
function err () {
    echo $* > "/dev/stderr"
}


function replace_subscripts_placeholders() {
    local PROCESSING_FILENAME=
    echo "-- processing file $PROCESSING_FILENAME"
    while read script_line || [ -n "$script_line" ]; do
        local script_line_NO_LEAD_SPACE="$(echo -e "${script_line}" | sed -e 's/^[[:space:]]*//' | sed -e 's/^M$//')"
        if  [[ $script_line_NO_LEAD_SPACE == \@\@* ]] ; then
            local file_name="${script_line_NO_LEAD_SPACE#\@\@}"
            echo "-- found reference to file $file_name"
            if [ -f "$file_name" ]; then
                replace_subscripts_placeholders $file_name
            else
                err_msg="WARNING: Could not find the referenced file $file_name"
                echo "-- $err_msg"
                err $err_msg
            fi          
        else
            echo "$script_line"
        fi
    done < $PROCESSING_FILENAME 
}

if test -z "" ; then
    err "Usage: oracle-script-compressor.sh {file_name_to_process} [> output_file]"
    err "  Be aware, if the referenced files within {file_name_to_process} are not specified by absolute paths, you have to start the script from corresponding directory."
    err "  If the part [> output_file] is omitted, then this script writes to standard output"
    err "  If the part [>> output_file] is used, then the result will be appended to output_file it it exists before the processing"
else
    if [ -f "" ]; then
        replace_subscripts_placeholders 
    else
        echo "file  does not exist"
    fi
fi