unix 使用shell,如何提取(以分隔变量)由“=”和空格包围的值?

pkln4tw6  于 2022-11-04  发布在  Unix
关注(0)|答案(2)|浏览(178)

例如,我有一个字符串/something an-arg=some-value another-arg=another-value
an-arg的值提取到一个变量中,将another-arg的值提取到另一个变量中,最直接的方法是什么?
为了更好地举例说明,这就是我需要发生的:

STRING="/something an-arg=some-value another-arg=another-value"
AN_ARG=... # <-- do some magic here to extract an-arg's value
ANOTHER_ARG=... # <-- do some magic here to extract another-arg's value
echo $AN_ARG # should print `some-value`
echo $ANOTHER_ARG # should print `another-value`

因此,我一直在寻找一种简单/直接的方法来实现这一点,我尝试了:

ARG_NAME="an-arg="
AN_ARG=${STRING#*$ARG_NAME}

但是这个解决方案的问题是,它将打印an-arg之后的所有内容,包括第二个参数的名称和它的值,例如some-value another-arg=another-value

pgvzfuti

pgvzfuti1#

让数据集任意变量会带来很大的安全风险。您应该给您生成的变量加前缀(前缀中至少有一个小写字符,以将生成的变量保留在POSIX为应用程序保留的名称空间中),或者将它们放在一个关联数组中;下面的第一个示例执行后者。

生成关联数组

正如您在https://ideone.com/cKcMSM上看到--


# !/usr/bin/env bash

# ^^^^- specifically, bash 4.0 or newer; NOT /bin/sh

declare -A vars=( )

re='^([^=]* )?([[:alpha:]_-][[:alnum:]_-]+)=([^[:space:]]+)( (.*))?$'
string="/something an-arg=some-value another-arg=another-value third-arg=three"
while [[ $string =~ $re ]]; do : "${BASH_REMATCH[@]}"
  string=${BASH_REMATCH[5]}
  vars[${BASH_REMATCH[2]}]=${BASH_REMATCH[3]}
done

declare -p vars # print the variables we extracted

...正确发射:

declare -A vars=([another-arg]="another-value" [an-arg]="some-value" [third-arg]="three" )

...因此您可以引用${vars[an-arg]}${vars[another-arg]}${vars[third-arg]}
这避免了原始建议中的错误,在原始建议中,字符串可以设置对系统有意义的变量--更改PATHLD_PRELOAD或其他安全敏感值。

生成前缀名称

要以另一种方式执行此操作,可能看起来像这样:

while [[ $string =~ $re ]]; do : "${BASH_REMATCH[@]}"
  string=${BASH_REMATCH[5]}
  declare -n _newVar="var_${BASH_REMATCH[2]//-/_}" || continue
  _newVar=${BASH_REMATCH[3]}
  unset -n _newVar
  declare -p "var_${BASH_REMATCH[2]//-/_}"
done

...如您在https://ideone.com/zUBpsC中看到的那样,创建了三个单独的变量,每个变量的名称都带有var_前缀:

declare -- var_an_arg="some-value"
declare -- var_another_arg="another-value"
declare -- var_third_arg="three"
vlju58qv

vlju58qv2#

假设条件:

  • OP理解CharlesDuffy概述的所有问题,但仍需要独立变量
  • 所有变量名称都要大写
  • 连字符(-)转换为下划线(_
  • 变量名和关联值都不包含嵌入白色

一个使用名称引用的bash想法:

unset newarg AN_ARG ANOTHER_ARG 2>/dev/null
STRING="/something an-arg=some-value another-arg=another-value"

read -ra list <<< "${STRING}"                                   # read into an array; each space-delimited item is a new entry in the array

# typeset -p list                                                # uncomment to display contents of the list[] array

regex='[^[:space:]]+=[^[:space:]]+'                             # search pattern: <var>=<value>, no embedded spaces in <var> nor <value>

for item in "${list[@]}"                                        # loop through items in list[] array
do
    if [[ "${item}" =~ $regex ]]                                # if we have a pattern match (<var>=<val>) then ...
    then
        IFS="=" read -r ndx val <<< "${BASH_REMATCH[0]}"        # split on '=' and read into variables ndx and val
        declare -nu newarg="${ndx//-/_}"                        # convert '-' to '_' and assign uppercased ndx to nameref 'newarg'
        newarg="${val}"                                         # assign val to newarg
    fi
done

这将生成:

$ typeset -p AN_ARG ANOTHER_ARG
declare -- AN_ARG="some-value"
declare -- ANOTHER_ARG="another-value"

注意事项:

  • 一旦for循环处理完成,访问新变量将需要预先知道新变量的名称
  • 使用关联数组来管理新变量的列表使得for循环后的访问变得相当容易(例如,新变量名只是关联数组的索引)

相关问题