【问题标题】:Bash read array from an external fileBash 从外部文件读取数组
【发布时间】:2011-01-13 21:12:51
【问题描述】:

我设置了一个同样需要用户输入的 Bash 菜单脚本。 这些输入被写入(附加到)一个名为 var.txt 的文本文件,如下所示:

input[0]='192.0.0.1'
input[1]='username'
input[2]='example.com'
input[3]='/home/newuser' 

现在我想要完成的是能够从类似这样的脚本中读取 var.txt:

useradd var.txt/${input[1]}

现在我知道仅以它为例是行不通的。

提前致谢, 乔

【问题讨论】:

    标签: bash


    【解决方案1】:

    使用bash's readarray statement。 (这是我能找到的在数组元素中动态放置空格的唯一方法。)您需要 var.txt 文件来简单地包含数组元素,每行一个,不包含赋值语句。

    readarray -t input < var.txt
    

    如需更多信息,请尝试help readarray(然后它会告诉您尝试help mapfile)。

    这是我的测试:

    echo -e "a\nb c\nd" > var.txt
    readarray input < var.txt 
    for item in "${input[@]}"; do echo $item; done
    

    打印:

    a
    b c
    d
    

    注意cat var.txt | readarray -t input 不起作用。我认为这是因为 input 变量的范围超出了范围。

    【讨论】:

    • 通常在 bash 数组中,空格被视为分隔符并成为不同的数组元素。那么读取文件时的行为并不一致?
    • 在我之前的评论中,我指的是复合赋值 name=(value1 value2 ...)
    【解决方案2】:

    如果整个 var.txt 文件只包含您所指出的与 Bash 兼容的变量分配,您可能只需 source 它,以使这些变量在新的 Bash 脚本中可用:

    source var.txt
    
    useradd ${input[1]}
    

    但是,这将覆盖任何现有的同名变量。 Command substitution 可以用来避免这种情况,通过选择特定的变量:

    input[1]="$(grep '^input\[1\]=' var.txt | sed "s|[^=]*='\(.*\)'|\1|")"
    

    它允许重命名变量,尽管您必须为每个感兴趣的变量执行此操作。它实质上是从var.txt 文件中提取变量的值并将其分配给一个新变量。请参阅 grep manual pagesed info page 了解有关它们的使用的更多信息。

    Process substitution 可能允许更简单的表达式:

    source <(grep '^input\[[0-9]*\]=' var.txt)
    
    useradd ${input[1]}
    

    这将允许您只导入感兴趣的定义,尽管您必须注意不需要的变量覆盖。

    【讨论】:

    • 我大约一个小时后回家时会尝试的。是的,它只包含与 Bash 兼容的变量赋值。
    • 感谢这些链接,那里有很多非常有用的信息。
    【解决方案3】:

    您可以将变量提取封装在一个函数中,并利用declare 在函数内部使用时创建局部变量这一事实。每次调用该函数时,此技术都会读取文件。

    readvar () {
        # call like this: readvar filename variable
        while read -r line
        do
            # you could do some validation here
            declare "$line"
        done < "$1"
        echo ${!2}
    }
    

    给定一个名为“data”的文件,其中包含:

    input[0]='192.0.0.1'
    input[1]='username'
    input[2]='example.com'
    input[3]='/home/newuser'
    foo=bar
    bar=baz
    

    你可以这样做:

    $ a=$(readvar data input[1])
    $ echo "$a"
    username
    $ readvar data foo
    bar
    

    这将读取一个数组并重命名它:

    readarray () {
        # call like this: readarray filename arrayname newname
        # newname may be omitted and will default to the existing name
        while read -r line
        do
            declare "$line"
        done < "$1"
        local d=$(declare -p $2)
        echo ${d/#declare -a $2/declare -a ${3:-$2}};
    }
    

    例子:

    $ eval $(readarray data input output)
    $ echo ${output[2]}
    example.com
    $ echo ${output[0]}
    192.0.0.1
    $ eval $(readarray data input)
    $ echo ${input[3]}
    /home/newuser
    

    这样做,您只需调用一次函数,整个数组就可用,而不必进行单独的查询。

    【讨论】:

    • 哇!谢谢,我还没有机会测试这些,但我相信这肯定会适用于我想要完成的工作。自动化的服务器安装和配置——复制系统的必备条件!周末应该有时间测试一下。谢谢你们!
    • @jmituzas:请注意,在 Bash 4 中有一个名为“readarray”的内置函数,它是“mapfile”的同义词。这些命令将文件中的行读入数组。他们没有按照我的回答进行变量设置,但您可能会融合这些技术。
    • 太棒了!所有这些版本都在很多方面帮助了我。
    猜你喜欢
    • 2023-01-30
    • 1970-01-01
    • 2014-06-19
    • 2012-03-12
    • 2012-10-28
    • 2012-06-05
    • 2012-01-12
    • 1970-01-01
    相关资源
    最近更新 更多