【问题标题】:Check variables with loop in Bash在 Bash 中使用循环检查变量
【发布时间】:2015-09-22 12:10:25
【问题描述】:

我构建了一个脚本,您可以在其中设置特定文件中的变量。

现在我想编写脚本检查文件中的所有变量是否不为空/未设置。

这是一个示例文件:

#variables.tmp
export foo=1
export bar=

这是我的代码,我试图找出它是否全部设置:

#!/bin/bash

PATHTOVARIABLES=/usr/local

#read variables
source $PATHTOVARIABLES/variables.tmp

#seperate comments from variables in file export.tmp
cat $PATHTOVARIABLES/variables.tmp | grep export > $PATHTOVARIABLES/export.tmp

#get variables in form "${var}"
sed -i "s/export /\"\$\{/g" $PATHTOVARIABLES/export.tmp
sed -i "s/=.*/\}\"/g" $PATHTOVARIABLES/export.tmp

#for-loop to read in variables
for i in `cat $PATHTOVARIABLES/export.tmp`
do

#check if variables are set or not
  if [ -z $i ]; then
    echo "Variable " $i " set"
  else
    echo " Variable not set"
  fi

done

rm $PATHTOVARIABLES/export.tmp

作为回报,无论变量是否设置,我都会得到“未设置变量”...

我使用了在那里找到的if 条件:https://serverfault.com/questions/7503/how-to-determine-if-a-bash-variable-is-empty

您能解释一下我的代码有什么问题吗?我是 bash 脚本的新手,所以请耐心等待 ;-)

【问题讨论】:

  • 它不工作吗?什么不工作?通过shellcheck.net 运行您的代码并修复它列出的问题(请参阅Bash FAQ 001 以替换您的 for 循环)。
  • 您是否仔细检查过任何个中间结果?在您的sed 之后的export.tmp 中有什么? i 包含什么? 为什么每个愿意帮助你的人都必须单独解决这个问题?
  • 您是否正在使用对/usr/local 具有写入 访问权限的用户测试 脚本?真的吗?
  • 你使用的是什么版本的bash
  • 我想要的是if [ -z "${foo}" ]; then。我认为这是可行的,因为i 包含字符串"${foo}"。我会试试 DevSolar 解决方案

标签: bash loops variables


【解决方案1】:

首先,请注意,根据定义,变量是在source 命令之后设置的; bar= 将变量设置为空字符串。

不需要grep 或临时文件;你可以迭代 覆盖bash 中的文件,并在读取时检查每个变量 文件。使用间接参数扩展来查找以字符串形式命名的参数的值。

#!/bin/bash

PATHTOVARIABLES=/usr/local

#read variables
source $PATHTOVARIABLES/variables.tmp

# Get the name of each exported value
while IFS='= ' read tag name value; do
    [[ $tag == export ]] || continue
    # Indirect expansion: get the value of
    # the parameter whose name is $name
    value=${!name}
    if [[ -z $value ]]; then
        echo "$name has empty value"
    else
       echo "$name has value ${!name}"
    fi
done < "$PATHTOVARIABLES/variables.tmp"

您可能需要考虑一些您没有明确提及的特殊情况:单个export 命令可以设置多个变量的值,而export 命令可以导出一个或多个名称而无需实际为它们设置一个值。

【讨论】:

    【解决方案2】:
    PATHTOVARIABLES=/usr/local
    

    要求对系统目录进行写访问绝不是一个好主意。我冒昧地将其重新定义为我家目录中的某些内容。

    source $PATHTOVARIABLES/variables.tmp
    

    此时,foo 设置为 1,而 bar 未设置。

    cat $PATHTOVARIABLES/variables.tmp | grep export > $PATHTOVARIABLES/export.tmp
    
    #get variables in form "${var}"
    sed -i "s/export /\"\$\{/g" $PATHTOVARIABLES/export.tmp
    sed -i "s/=.*/\}\"/g" $PATHTOVARIABLES/export.tmp
    

    此时export.tmp 包含:

    "${foo}"
    "${bar}"
    

    按设计工作。

    #for-loop to read in variables
    for i in `cat $PATHTOVARIABLES/export.tmp`
    do
    

    此时i 包含字符串"${foo}"(并且,在第二个循环中,"${bar}")。

    #check if variables are set or not
    if [ -z $i ]; then
    

    不,您正在检查变量 i 是否为空。其中包含"${foo}",不为空,因此条件为假,所以...

    echo " Variable not set"
    

    计算机完全按照您告诉他们的事情去做,而不是您希望他们做的事情。 ;-)

    我通过在适当的位置添加 echo $fooecho $barcat $PATHTOVARIABLES/export.tmpecho $i 行来解决这个问题,从而显着缩小了脚本无法满足预期的位置。你可以自己做这个,给出一个更短的问题......

    如果您正在寻找一种方法来检查 i 中的变量 named 是否已设置, 那么您要查找的命令是eval(以下警告)。

    for i in `cat $PATHTOVARIABLES/export.tmp`
    do
        eval "tmp=${i}"    # expands to tmp="${foo}" / tmp="${bar}" and gets evaluated
    
        if [[ -z $tmp ]]
        then
            echo "Variable ${i} is not set."
        else
            echo "Variable ${i} is set to ${tmp}."
        fi
    done
    

    注意:

    在外部输入上使用eval潜在危险。如果攻击者能够修改您的脚本提供给eval 的任何内容(在本例中为文件variables.tmp),那么他可以使您的脚本以执行脚本的任何用户的权限执行命令(在你的情况,root——这就是为什么测试 root 不是一个好主意)。

    我看不出在您的具体情况下会发生这种情况,但我询问了用户 chepner,他似乎不同意。

    【讨论】:

    • @chepner:你知道吗?而认为他在寻找什么?
    • 因为你只是将它用于间接变量扩展,bash中有一个运算符。用户显然对他定义的变量知之甚少,不知道它们的名字是什么,更不用说这些值是否可以安全地传递给eval。我正在等待找出他使用哪个版本的bash 来建议最佳安全答案。
    • 感谢您的解释!我切换到我的 Homedir,但我通过用户 root 对其进行了测试,所以我有写访问权限。我想要的是if [ -z "${foo}" ]; then 我认为这是可行的,因为i 包含字符串"${foo}"。是否有解决方案可以检查i 的内容而不是i 本身。 //编辑我会试试你的解决方案。
    • @chepner:你能告诉我一个variables.tmp 的示例行,它将在这里利用eval,并按照OP 的脚本进行预处理?
    • @chepner:我的 bash 版本是 4.3.30 版
    猜你喜欢
    • 2017-06-15
    • 2020-10-20
    • 2019-02-21
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 2014-01-07
    • 1970-01-01
    • 2020-09-12
    相关资源
    最近更新 更多