无法在unix shell脚本中从config.txt文件读取多个数据库连接的详细信息

2skhul33  于 2023-04-07  发布在  Shell
关注(0)|答案(1)|浏览(114)

我试图从shell脚本实现以下要求,但没有得到适当的输出。
要求:我有一个主文件夹,其中包括两个子文件夹和子文件夹内,我有SQL脚本,我需要在各自的数据库执行。我在config.txt文件中给出了所有数据库连接的详细信息。下面是文件夹结构

Main folder
  Folder1/first.sql
  Folder2/second.sql
  config.txt

Config.txt内容

DB_USER:FIRST
DB_PASSWORD:password
DB_HOST:10.192.1.162
DB_PORT:1592
DB_SERVICE_NAME:abc_1

DB_USER:SECOND
DB_PASSWORD:password
DB_HOST:10.192.1.162
DB_PORT:1592
DB_SERVICE_NAME:abd_1

shell 脚本

set +x
    
    #change directory to the main folder
    cd /home/Test
    
    # Loop through all config files in the main folder
    for config_file in $(find . -maxdepth 2 -name "config.txt"); do
       source "$config_file" 
    
     
    
    echo "DB_USER:$DB_USER"
    echo "DB_PASSWORD:$DB_PASSWORD"
    echo "DB_SERVICE_NAME:$DB_SERVICE_NAME"
    
    
    # Change directory to the folder containing the SQL scripts
    folder=$(dirname "$config_file")
    cd "$folder"
    
    #echo "DB_USER:$DB_USER"
    #echo "DB_PASSWORD:$DB_PASSWORD"
    #echo "DB_SERVICE_NAME:$DB_SERVICE_NAME"
    echo "Current directory: $(pwd)"
    echo "List of SQL files:"
    find . -name "*.sql"
    echo "Processing SQL files. Please wait.."
    
    # Loop through all SQL scripts in the current folder and its subfolders
    sql_files=$(find . -name "*.sql")
    if [ -n "$sql_files" ]; then
    while IFS= read -r file; do
                echo "Executing SQL script $file"
                echo "DB_USER: $DB_USER"
                echo "DB_SERVICE_NAME:$DB_SERVICE_NAME"
        sqlplus -s "$DB_USER/$DB_PASSWORD@$DB_SERVICE_NAME" < "$file" > /dev/null
                
                if [ $? -ne 0 ]; then
                    echo "Error executing $file"
                    exit 1
                fi
        done <<< "$sql_files"
    else
    echo "No SQL files found in the current directory"
    fi
    # Change back to the main folder
    cd ..
    done
    
    echo "All SQL scripts executed successfully for all connections"
    exit 0

问题:
当我尝试执行上面的shell脚本时,它只需要第二个DB连接的详细信息,并执行SQL脚本两次。
SQL脚本
第一个SQL文件

create table test(colA number,colB number);
insert into test values(1,2);
commit;

GRANT SELECT ON FIRST.TEST TO READ_ROLE;

第二个SQL文件

create table test(colA number,colB number);
insert into test values(1,2);
commit;

GRANT SELECT ON SECOND.TEST TO READ_ROLE;
ljsrvy3e

ljsrvy3e1#

这里的问题是,您将两个SQL配置数据存储在一个具有相同变量名的config.txt文件中:

DB_USER:FIRST
DB_PASSWORD:password
DB_HOST:10.192.1.162
DB_PORT:1592
DB_SERVICE_NAME:abc_1

DB_USER:SECOND         #<------------ Same Variable DB_USER as used above
DB_PASSWORD:password   #<------------ Same Variable DB_PASSWORD as used above
DB_HOST:10.192.1.162   #<------------ Same Variable DB_HOST as used above
DB_PORT:1592           #<------------ Same Variable DB_PORT as used above
DB_SERVICE_NAME:abd_1  #<------------ Same Variable DB_SERVICE_NAME as used above

在将此文件作为source config.txt源时,最后分配给变量的值将被存储并将生效,在这种情况下,变量将始终在此文件源的活动shell会话中保持以下值:

DB_USER:SECOND
DB_PASSWORD:password
DB_HOST:10.192.1.162
DB_PORT:1592
DB_SERVICE_NAME:abd_1

上述变量的第一个赋值将被覆盖。
要解决这个问题,您必须将数据库变量存储到不同的文件中,例如config-1.txtconfig-2.txt
此外,逻辑应该被编写为使得相应的配置文件应该在执行SQL文件之前获得源。
为了实现这一点,许多可能解决方案中的一种可能性是:
所有的sql文件和配置文件都可以存储在两个不同的bash数组中,并且根据数组索引,在执行SQL文件指令之前应该获取配置文件。
我已经发布了一个修改过的shell脚本:

#change directory to the main folder
    cd /home/Test
    
    # Loop through all config files in the main folder
    config_files=($(find . -maxdepth 2 -name "config*.txt"))
    echo "Config Files: ${config_files[0]} and ${config_files[1]}"
    
    # Change directory to the folder containing the SQL scripts
    folder=$(dirname "$config_file")
    cd "$folder"
    
    echo "Current directory: $(pwd)"
    echo "Processing SQL files, Please wait..."
    
    # Loop through all SQL scripts in the current folder and its subfolders
    sql_files=($(find . -name "*.sql"))
    for sql_f in "${!sql_files[@]}"; do
        echo "$sql_f ==> ${sql_files[sql_f]}"
        echo "$sql_f ==> ${config_files[sql_f]}"
        source ${config_files[sql_f]}
        while IFS= read -r file; do
        echo "Executing SQL script $file"
        echo "DB_USER: $DB_USER"
        echo "DB_SERVICE_NAME:$DB_SERVICE_NAME"
        echo "sqlplus -s "$DB_USER/$DB_PASSWORD@$DB_SERVICE_NAME" < "$file" > /dev/null"
        if [ $? -ne 0 ]; then
            echo "Error executing $file"
            exit 1
        fi
        done <<< "${sql_files[sql_f]}"
    done
    # Change back to the main folder
    cd ..
    echo "All SQL scripts executed successfully for all connections"
    exit 0

目录结构如下所示:

MainFolder/
├── config-1.txt
├── config-2.txt
├── Folder1
│   └── first.sql
├── Folder2
│   └── second.sql
└── the-shell-script.sh

我希望这能解决你的问题。
更新:根据您的评论:
感谢您的回应,但在真实的情况下,我不知道有多少数据库连接,我需要添加在配置文件,所以我想给予所有的数据库细节在一个配置文件,然后通过所有的子文件夹迭代执行SQL脚本。
正如你提到的,在真实的场景中,数据库连接的数量是未知的。记住上面的要求,你需要遵循一些基于bash行为的结构。

  1. config.txt应包含所有数据库连接,但使用不同的变量名,例如DB_USER_0=FIRSTDB_PASSWORD_0=password_0DB_USER_1=SECOND
    1.包含SQL脚本first.sqlsecond.sql等的文件夹应按数字升序排列,如您在原始问题中提到的Folder1/first.sqlFolder2/second.sql
    请记住您的新要求(您在最初的问题中没有提到)和限制,您可以参考以下修改后的shell脚本,并根据您的需求使用它来增强功能:
#change directory to the main folder
cd /home/Test
# Loop through all config files in the main folder
config_files=$(find . -maxdepth 2 -name "config.txt")
echo "Config Files: ${config_files}"
source ${config_files}

# Change directory to the folder containing the SQL scripts
folder=$(dirname "$config_file")
cd "$folder"

echo "Current directory: $(pwd)"
echo "Processing SQL files, Please wait..."

# Loop through all SQL scripts in the current folder and its subfolders
sql_files=($(find . -name "*.sql" | sort -n))   # find all files ending with *.sql extension and store it in array named sql_files with abs path
for sql_f in "${!sql_files[@]}"; do # iterate through all the elements of sql_files
    echo "$sql_f ==> ${sql_files[sql_f]}"
        
    while IFS= read -r file; do
        DB_USER="DB_USER_$sql_f"        #expand environment variable DB_USER_0 and so on using iterator value $sql_f
        DB_PASSWORD="DB_PASSWORD_$sql_f"
        DB_HOST="DB_HOST_$sql_f"
        DB_PORT="DB_PORT_$sql_f"
        DB_SERVICE_NAME="DB_SERVICE_NAME_$sql_f"
        
        echo "Executing SQL script $file"
        echo "DB_USER: ${!DB_USER}"
        echo "DB_SERVICE_NAME: "${!DB_SERVICE_NAME}""
        echo "sqlplus -s "${!DB_USER}/${!DB_PASSWORD}@${!DB_SERVICE_NAME}" < "$file" > /dev/null"
        if [ $? -ne 0 ]; then
            echo "Error executing $file"
            exit 1
        fi
    done <<< "${sql_files[sql_f]}"
done
# Change back to the main folder
cd ..
echo "All SQL scripts executed successfully for all connections"
exit 0

相应的config.txt文件应采用以下格式:

DB_USER_0=ZERO
DB_PASSWORD_0=password_0
DB_HOST_0=10.192.1.162
DB_PORT_0=1592
DB_SERVICE_NAME_0=abc_0

DB_USER_1=FIRST
DB_PASSWORD_1=password_1
DB_HOST_1=10.192.1.162
DB_PORT_1=1592
DB_SERVICE_NAME_1=abc_1

DB_USER_2=SECOND
DB_PASSWORD_2=password_2
DB_HOST_2=10.192.1.162
DB_PORT_2=1592
DB_SERVICE_NAME_2=abc_2

相关问题