如何使用Bash引用文件中的变量?


151

我想为变量调用设置文件,如何在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等吗?

Answers:


241

简短的答案

使用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命令,获取和设置“环境变量”也可以实现此目的。

运行export并且echo $ENV应该是您访问变量所需要知道的全部。访问环境变量的方式与本地变量的方式相同。

要设置它们,请说:

export variable=value

在命令行。所有脚本都将能够访问该值。


config.sh是否必须具有执行权限才能工作?
拉米罗2014年

2
有没有一种方法可以source通过内容传递而不是提供文件来使用?好像some command | source不起作用...
Elliot Chance

1
没关系,我找到了解决方案并将其发布给其他人。
Elliot Chance

和还原数组,您必须分别存储每个数组入口值(不是完整的数组单行declare -p),就像这样someArray[3]="abc",依此类推……
Aquarius Power

1
@Ramiro不,不是。我检查了。:)
Matt Komarnicki

22

使用点甚至更短:

#!/bin/bash
. CONFIG_FILE

sudo -u wwwrun svn up /srv/www/htdocs/$production
sudo -u wwwrun svn up /srv/www/htdocs/$playschool

17
在脚本中使用它时,速记是不必要的,可能会造成混淆。为什么不使用full source命令来使之清楚?
Lyle

2
@Lyle因为您希望脚本不必不必要地偏离便携式POSIX语法?
人间

14

使用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

12

我在安全性cas方面有同样的问题,我在这里找到了解决方案

我的问题是,我想在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”命令并使用这些变量导入配置文件。'SOURCE path / to / file'但是此解决方案存在一些安全问题,因为源文件可以包含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该文件中的形式的构造(变量赋值语法),也可能只允许注释(尽管从技术上讲,注释并不重要)。因此,我们可以使用以下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

1
我尚未验证您的语法检查器以确保它正确地解决了所有情况,但是由于安全问题,到目前为止,这是最好的主意。
安吉洛

6
这还不够安全,您仍然可以这样做CMD="$(rm -fr ~/*)"
svlasov

感谢@svlasov,我认为这是一个严重的问题,我编辑了我的答案,以通过拒绝用于命令替换的字符来避免该类型的问题,例如(``the final CONFIG_SYNTAX="(^\s*#|^\s*$|^\s*[a-z_][^[:space:]]*=[^;&\(`]*$)"
Erman

还不够。foo=bar unleash_virus可以执行。注意foo=bar\ unleash_virusfoo="bar unleash_virus"并且foo=bar #unleash_virus是安全的。正确地进行清理并且不阻止任何无害的语法也不容易,特别是当您想到所有可能的引用和转义时。
卡米尔Maciorowski

9

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

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

参考


3

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

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

#!/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所示,我将通过以下两个参数:

  • "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}"

不是最有效的,但是使用较小的文件会非常干净。


2

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

some command | xargs

-1

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

#!/bin/sh
scr-var=value

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

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

这不起作用,它将在子进程中运行Bash脚本,然后丢失其在生命周期中创建的任何环境(包括变量)。也是src-var无效的标识符。
人间

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.