将文件中的键/值参数读入 shell 脚本

Posted

技术标签:

【中文标题】将文件中的键/值参数读入 shell 脚本【英文标题】:Reading key/value parameters from a file into a shell script 【发布时间】:2016-12-22 05:47:12 【问题描述】:

我的脚本几乎可以运行了。这样做的目的是从文件中获取定义的值,然后在运行时将这些值填充到 shell 脚本中。

请看看我这里有什么...

第一个文件:ab.sh

#!/bin/bash
USER_TYPE=$1 #IDENTIFY USER TYPE TYPE1,TYPE2,TYPE3,TYPE4
USERNAME=$2
PERMISSION_TYPE=$3 #IDENTIFY PERMISSION TYPE SELECT,UPDATE,DELETE,INSERT
TARGET_USER=$4
TARGET_TABLE=$5

if [ $USER_TYPE == 'TYPE1' ]
        then
cat Parameters.conf |while read USERNAME
do
sqlplus / as sysdba <<  E00
CREATE USER $USERNAME
DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP
ACCOUNT UNLOCK;
ALTER USER $USERNAME DEFAULT ROLE ALL;
GRANT CREATE SESSION TO $USERNAME;
GRANT CONNECT TO $USERNAME;
exit
E00
done

cat p.conf |while read PERMISSION_TYPE TARGET_SCHEMA TARGET_TABLE USERNAME
do
sqlplus / as sysdba > /home/o/output/output.log << E01
GRANT $PERMISSION_TYPE ON $TARGET_USER.$TARGET_TABLE TO $USERNAME;
E01
done
fi

这是定义值的文件Parameters.conf,应该来自...

Parameters.conf

USER_TYPE TYPE1
USERNAME NEWUSER
PERMISSION_TYPE SELECT,UPDATE
TARGET_USER TESTUSER
TARGET_TABLE ABC

【问题讨论】:

不要为你自己的变量使用全大写的名称——这会使它们与操作系统和 shell 定义的环境变量冲突,这些变量仅限于该命名空间(例如,有一个USER 预设在你在这里覆盖的 bash 中)。请参阅pubs.opengroup.org/onlinepubs/009695399/basedefs/…,第四段,了解围绕环境变量名称的 POSIX 约定(以及扩展的 shell 变量名称,因为它们共享一个命名空间)。 我实际上没有在脚本中使用的 USER 变量。哎呀 当然;也就是说,重点更多是关于约定——如果您使用userusername 而不是USERUSERNAME,则您无需监管您的操作系统或shell 是哪些特定变量或没有设置和是否有冲突。 ...顺便说一句,这将与哪个版本的 bash 一起运行?从 4.0 开始,有可用的关联数组功能,因此我们可以将从文件中读取的变量保存在与 shell 变量完全不同的命名空间中。如果需要与其他版本兼容,可以使用前缀或后缀来实现相同的效果。 【参考方案1】:

第一选择:关联数组

这需要 bash 4.0 或更新版本来支持declare -A;其他选项见下文。

#!/bin/bash

# first, read your key/value pairs into shell variables
declare -A v=( )
while read -r var value; do
  v[$var]=$value
done < Parameters.conf

# second, perform a command that depends on them
sqlplus / as sysdba <<  E00
CREATE USER $v[USERNAME]
DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP
ACCOUNT UNLOCK;
ALTER USER $v[USERNAME] DEFAULT ROLE ALL;
GRANT CREATE SESSION TO $v[USERNAME];
GRANT CONNECT TO $v[USERNAME];
exit
E00

sqlplus / as sysdba > /home/o/output/output.log << E01
GRANT $v[PERMISSION_TYPE] ON $v[TARGET_USER].$v[TARGET_TABLE] TO $v[USERNAME];
E01

要点:

在BashFAQ #6 中描述了分配给一个shell 变量它本身在一个变量中命名;对于关联数组也是如此。 重定向需要使用while read key value; do ...; done &lt;input 而不是cat input | while read key value; do ...; done 来避免BashFAQ #24 的错误。 实际的sqlplus 调用不应在循环内,因为循环体在文件中的每一行运行一次。由于您希望所有在运行sqlplus 之前读取文件的所有行(以及分配的所有变量),因此循环应该在sqlplus 被调用之前完全完成。 使用前缀或关联数组可确保来自配置文件的变量不会覆盖PATHLD_PRELOAD 等系统环境变量。

第二选择:前缀命名空间

#!/bin/bash

while read -r var value; do
  printf -v "v_$var" %s "$value"
done <Parameters.conf

# second, perform a command that depends on them
sqlplus / as sysdba <<  E00
CREATE USER $v_USERNAME
DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP
ACCOUNT UNLOCK;
ALTER USER $v_USERNAME DEFAULT ROLE ALL;
GRANT CREATE SESSION TO $v_USERNAME;
GRANT CONNECT TO $v_USERNAME;
exit
E00

sqlplus / as sysdba > /home/o/output/output.log << E01
GRANT $v_PERMISSION_TYPE ON $v_TARGET_USER.$v_TARGET_TABLE TO $v_USERNAME;
E01

【讨论】:

所以它会是:同时读取 Parameter1 parameter2 依此类推 然后在最后我会做 非常正确。您可以使用while read -r parameter1 parameter2 ... 来避免read 在输入中解析(并因此删除)反斜杠的默认行为。 (即使您不期望反斜杠,除非您明确有理由想要它,否则关闭该行为通常是有意义的)。 非常感谢。我很感激这一点。我现在完全明白了! 很高兴为您提供帮助!请接受我对之前没有给予足够关注的歉意。 (我还进行了修改以尝试展示两种不同的方法来将配置变量与其他变量分开——关联数组,其他语言可能将其称为“哈希”或“映射”;以及使用前缀命名空间)。

以上是关于将文件中的键/值参数读入 shell 脚本的主要内容,如果未能解决你的问题,请参考以下文章

将参数从 Qt 传递到 shell 脚本文件

shell 自定义带参数函数

一个脚本就能明白Shell 脚本中的位置参数的含义

shell定义带参数的函数

Shell中的特殊变量

shell脚本读取配置文件参数