【问题标题】:Bash script not recognizing existing fileBash 脚本无法识别现有文件
【发布时间】:2023-03-13 16:17:02
【问题描述】:

我必须编写一个简单的 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=$1
    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 "$1" ; 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 "$1" ]; then
        replace_subscripts_placeholders $1
    else
        echo "file $1 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 中仍然存在问题 - 文件存在性的测试总是返回 false:

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 显示目录总是正确的......???) - 任何帮助或指针将不胜感激。

【问题讨论】:

  • 欢迎您阅读How to Ask,更重要的是阅读minimal reproducible example。
  • 我不知道if 测试(正如@Nic3500 所说,您确实需要删除与问题无关的所有内容——这对于除您以外的其他人进行调试),但我确实看到了另一个问题:不要使用. 命令来运行函数,这不是它的作用。 . 命令在当前 shell 中内联运行命令从脚本文件(非常类似于source 命令)。我还建议将 set -x 放在问题部分之前,以获取 shell 在那里执行的操作的执行跟踪。
  • @GordonDavisson 感谢回复 - . 只是绝望的表达:-)。当然没用过我也试过,没影响。
  • 一般来说我很抱歉 - 我认为,这个例子足够小:-) 冗长是由调试消息引起的,这对代码并不重要,但如果重现问题会很有帮助 - 我想,每个想复制它的人都会以类似的方式进行。但是非常感谢您的提示,我会尽量减少冗长的内容。

标签: bash oracle file-exists


【解决方案1】:

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

while read script_line

不仅将行中的给定文件名放入变量中,前面还有字符@@

@@a.sql

还有&lt;CR&gt; 字符 - 变量中的值就是值

@@a.sql&lt;CR&gt;

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

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


function replace_subscripts_placeholders() {
    local PROCESSING_FILENAME=$1
    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 "$1" ; 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 "$1" ]; then
        replace_subscripts_placeholders $1
    else
        echo "file $1 does not exist"
    fi
fi

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-22
    • 2015-09-10
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 2017-02-14
    • 2021-10-31
    • 1970-01-01
    相关资源
    最近更新 更多