【问题标题】:How to reference a file for variables using Bash?如何使用 Bash 为变量引用文件?
【发布时间】:2011-07-10 20:16:07
【问题描述】:

我想调用一个变量的设置文件,我该如何在 bash 中做到这一点?

所以设置文件将定义变量(例如:CONFIG.FILE):

production="liveschool_joe"
playschool="playschool_joe"

脚本会使用其中的那些变量

#!/bin/bash
production="/REFERENCE/TO/CONFIG.FILE"
playschool="/REFERENCE/TO/CONFIG.FILE"
sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

我怎样才能让 bash 做这样的事情?我必须使用 awk/sed 等吗?

【问题讨论】:

    标签: bash variables configuration-files


    【解决方案1】:

    简短的回答

    使用source 命令。


    一个使用source的例子

    例如:

    config.sh

    #!/usr/bin/env bash
    production="liveschool_joe"
    playschool="playschool_joe"
    echo $playschool
    

    script.sh

    #!/usr/bin/env bash
    source config.sh
    echo $production
    

    请注意,此示例中sh ./script.sh 的输出为:

    ~$ sh ./script.sh 
    playschool_joe
    liveschool_joe
    

    这是因为source 命令实际运行程序。 config.sh 中的所有内容都会被执行。


    另一种方式

    您可以使用内置的export 命令并获取和设置“环境变量”也可以完成此操作。

    运行exportecho $ENV 应该是您访问变量所需了解的全部内容。访问环境变量的方式与访问局部变量的方式相同。

    要设置它们,说:

    export variable=value
    

    在命令行。所有脚本都可以访问该值。

    【讨论】:

    • 必须 config.sh 具有执行权限才能使其工作吗?
    • 要恢复数组,你必须单独存储每个数组条目值(不是来自declare -p的完整数组单行),就像someArray[3]="abc",等等......跨度>
    • @Ramiro 不,它没有。我检查了。 :)
    • 在我的情况下,源命令会引发错误,这取决于显然使用的是哪个 shell - stackoverflow.com/a/13702876/2223138
    • 可能值得注意的是,source 是 bash 中 POSIX . 的同义词。如果您的目标是脚本的可移植性,您可以使用 POSIX 点。
    【解决方案2】:

    使用点更短:

    #!/bin/bash
    . CONFIG_FILE
    
    sudo -u wwwrun svn up /srv/www/htdocs/$production
    sudo -u wwwrun svn up /srv/www/htdocs/$playschool
    

    【讨论】:

    • 在脚本中使用它时,速记是不必要的并且可能会造成混淆。为什么不使用完整的source 命令来明确?
    • @Lyle 因为你希望你的脚本在你不需要的时候不要无缘无故地偏离可移植的 POSIX 语法?
    【解决方案3】:

    使用source 命令导入其他脚本:

    #!/bin/bash
    source /REFERENCE/TO/CONFIG.FILE
    sudo -u wwwrun svn up /srv/www/htdocs/$production
    sudo -u wwwrun svn up /srv/www/htdocs/$playschool
    

    【讨论】:

      【解决方案4】:

      我在安全方面也遇到了同样的问题,我找到了解决方案here

      我的问题是,我想在 bash 中编写一个部署脚本,其中包含一个配置文件,其中包含类似这样的路径。

      ################### Config File Variable for deployment script ##############################
      
      VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
      VAR_CONFIG_FILE_DIR="/home/erman/config-files"
      VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"
      

      现有的解决方案包括使用“SOURCE”命令并使用这些变量导入配置文件。 '源路径/到/文件' 但是这个解决方案存在一些安全问题,因为源文件可以包含 Bash 脚本可以包含的任何内容。 这会产生安全问题。当您的脚本获取其配置文件时,恶意软件人可以“执行”任意代码。

      想象一下这样的事情:

       ################### Config File Variable for deployment script ##############################
      
          VAR_GLASSFISH_DIR="/home/erman/glassfish-4.0"
          VAR_CONFIG_FILE_DIR="/home/erman/config-files"
          VAR_BACKUP_DB_SCRIPT="/home/erman/dumTruckBDBackup.sh"; rm -fr ~/*
      
          # hey look, weird code follows...
          echo "I am the skull virus..."
          echo rm -fr ~/*
      

      为了解决这个问题,我们可能希望在该文件中只允许 NAME=VALUE 形式的构造(变量赋值语法),也许还有 cmets(虽然从技术上讲,cmets 并不重要)。因此,我们可以使用egrep 命令等效于grep -E 来检查配置文件。

      这就是我解决问题的方法。

      configfile='deployment.cfg'
      if [ -f ${configfile} ]; then
          echo "Reading user config...." >&2
      
          # check if the file contains something we don't want
          CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(\`]*$)"
          if egrep -q -iv "$CONFIG_SYNTAX" "$configfile"; then
            echo "Config file is unclean, Please  cleaning it..." >&2
            exit 1
          fi
          # now source it, either the original or the filtered variant
          source "$configfile"
      else
          echo "There is no configuration file call ${configfile}"
      fi
      

      【讨论】:

      • 我尚未验证您的语法检查器以确保它正确地考虑所有情况,但由于安全问题,这是迄今为止最好的主意。
      • 这还不够安全,你仍然可以这样做CMD="$(rm -fr ~/*)"
      • 谢谢@svlasov,我认为这是一个严重的问题,我通过拒绝用于命令替代的字符(如( 和```最后的CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
      • 还是不够。 foo=bar unleash_virus 可以执行。注意foo=bar\ unleash_virusfoo="bar unleash_virus"foo=bar #unleash_virus 是安全的。无论如何,要正确清理并且不阻止一些无害的语法并不容易,尤其是当您想到所有可能的引用和转义时。
      • 已将其更新为不阻止数组? CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$|[a-z_][^[:space:]]*\+?=\([^;&\(`]*\)$)"
      【解决方案5】:

      在 Bash 中,获取一些命令的输出,而不是文件:

      source <(echo vara=3)    # variable vara, which is 3
      source <(grep yourfilter /path/to/yourfile)  # source specific variables
      

      reference

      【讨论】:

        【解决方案6】:

        将参数文件转换为环境变量

        通常我会进行解析而不是采购,以避免文件中某些工件的复杂性。它还为我提供了专门处理报价和其他事情的方法。我的主要目标是将 '=' 之后的任何内容保留为文字,甚至是双引号和空格。

        #!/bin/bash
        
        function cntpars() {
          echo "  > Count: $#"
          echo "  > Pars : $*"
          echo "  > par1 : $1"
          echo "  > par2 : $2"
        
          if [[ $# = 1 && $1 = "value content" ]]; then
            echo "  > PASS"
          else
            echo "  > FAIL"
            return 1
          fi
        }
        
        function readpars() {
          while read -r line ; do
            key=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\1/')
            val=$(echo "${line}" | sed -e 's/^\([^=]*\)=\(.*\)$/\2/' -e 's/"/\\"/g')
            eval "${key}=\"${val}\""
          done << EOF
        var1="value content"
        var2=value content
        EOF
        }
        
        # Option 1: Will Pass
        echo "eval \"cntpars \$var1\""
        eval "cntpars $var1"
        
        # Option 2: Will Fail
        echo "cntpars \$var1"
        cntpars $var1
        
        # Option 3: Will Fail
        echo "cntpars \"\$var1\""
        cntpars "$var1"
        
        # Option 4: Will Pass
        echo "cntpars \"\$var2\""
        cntpars "$var2"
        

        请注意我必须做的一个小技巧,将引用的文本视为带有空格的单个参数到我的cntpars 函数。需要额外的一级评估。如果我不这样做,就像在选项 2 中那样,我会传递 2 个参数,如下所示:

        • "value
        • content"

        命令执行期间的双引号会导致参数文件中的双引号被保留。因此第三个选项也失败了。

        另一种选择当然是不提供双引号中的变量,如选项 4,然后确保在需要时引用它们。

        只是需要记住的一点。

        实时查询

        我喜欢做的另一件事是实时查找,避免使用环境变量:

        lookup() {
        if [[ -z "$1" ]] ; then
          echo ""
        else
          ${AWK} -v "id=$1" 'BEGIN { FS = "=" } $1 == id { print $2 ; exit }' $2
        fi
        }
        
        MY_LOCAL_VAR=$(lookup CONFIG_VAR filename.cfg)
        echo "${MY_LOCAL_VAR}"
        

        不是最有效的,但较小的文件可以非常干净地工作。

        【讨论】:

          【解决方案7】:

          如果正在生成变量并且未将其保存到文件中,则无法将它们通过管道传输到 source。看似简单的方法是这样的:

          some command | xargs
          

          【讨论】:

            【解决方案8】:

            包含变量的脚本可以使用 bash 导入执行。 考虑 script-variable.sh

            #!/bin/sh
            scr-var=value
            

            考虑使用变量的实际脚本:

             #!/bin/sh
             bash path/to/script-variable.sh
             echo "$scr-var"
            

            【讨论】:

            • 这不起作用,它将在子进程中运行 Bash 脚本,然后丢失它在其生命周期内创建的任何环境(包括变量)。 src-var 也不是有效的标识符。
            【解决方案9】:

            为了防止命名冲突,只导入你需要的变量:

            variableInFile () {
                variable="${1}"
                file="${2}"
            
                echo $(
                    source "${file}";
                    eval echo \$\{${variable}\}
                )
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-09-12
              • 2011-04-22
              • 2013-07-04
              • 2011-02-18
              • 2011-08-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多