在bash字符串变量中展开大括号和通配符(不带eval)

在bash字符串变量中展开大括号和通配符(不带eval),bash,eval,code-injection,curly-braces,variable-expansion,Bash,Eval,Code Injection,Curly Braces,Variable Expansion,给定bash中的字符串变量(不是字符串),如何展开它的大括号(并对任何文件通配符(如星号)进行全局化),然后将结果展开存储在数组中 我知道这可以通过eval: #!/usr/bin/env bash string="{a,b}{1,2}" array=( $( eval echo $string ) ) echo "${array[@]}" #a1 a2 b1 b2 但是如果我们不信任string的内容,那么eval可能是危险的(比如,如果它是脚本的参

给定bash中的字符串变量(不是字符串),如何展开它的大括号(并对任何文件通配符(如星号)进行全局化),然后将结果展开存储在数组中

我知道这可以通过
eval

#!/usr/bin/env bash

string="{a,b}{1,2}"
array=( $( eval echo $string ) )
echo "${array[@]}"
#a1 a2 b1 b2
但是如果我们不信任
string
的内容,那么
eval
可能是危险的(比如,如果它是脚本的参数)。嵌入分号、引号、空格、任意命令等的
字符串
可能会打开脚本进行攻击

有没有更安全的方法在bash中进行此扩展?我怀疑以下所有方法都是同样不安全的扩展字符串的方法:

#!/usr/bin/env bash

eval echo $string

bash <<< "echo $string"

echo echo $string | bash

bash <(echo echo $string)
与标准库
glob
模块结合使用,可以实现您所需的功能。包装在shell中以供bash使用,这可能看起来像:

#!/usr/bin/env bash
case $BASH_VERSION in
  ''|[123].*|4.[012].*) echo "ERROR: bash 4.3+ required" >&2; exit 1;;
esac

# store Python code in a string
expand_py=$(cat <<'EOF'
try:
  import sys, glob, braceexpand
except ImportError as e:
  sys.stderr.write("Did you remember to install the braceexpand Python module?\n")
  raise e

for arg in sys.argv[1:]:
  for globexp in braceexpand.braceexpand(arg):
    glob_results = glob.glob(globexp)
    if len(glob_results) == 0:
      sys.stdout.write(globexp)
      sys.stdout.write('\0')
      continue
    else:
      sys.stdout.write(''.join(['%s\0' % result for result in glob_results]))
EOF
)

# shell wrapper for the above Python program
expand() {
  local item
  local -n dest_array=$1; shift

  dest_array=( )
  while IFS= read -r -d '' item; do
    dest_array+=( "$item" )
  done < <(python3 -c "$expand_py" "$@")
  unset -n dest_array
}

# actually demonstrate usage
expand yourArray '{a,b}{1,2}'
declare -p yourArray

数组指定会展开大括号展开,不需要
eval
!Try
arr=({1,2});declare-p arr
哦,等等,您是从一个字符串变量开始的。这行不通,因为大括号扩展发生在参数扩展之前。您从哪里获得
string
?也许有一种方法可以在单独的步骤中进行大括号扩展。实际上,我从一个字符串变量开始,而不是字符串,并希望将其扩展到数组中。在我的应用程序中,字符串变量通常较长且复杂,带有大括号、通配符等,并扩展为一个非常长的文件数组。字符串在脚本中的其他地方也以非扩展形式使用,例如,传递给其他shell命令,这些命令稍后将在预加路径等后进行扩展,因此重构代码以避免这种情况将是困难的。听起来像是传递已经扩展的列表,而不是像
'a{b,c}*.
这样的东西更可取。当然,这会使其他事情更加困难,但这是一种非黑客方法。除此之外,我真的很想看到问题的答案,而不是像我这样的评论(试图说服你不要做你想做的事:)
#!/usr/bin/env bash
case $BASH_VERSION in
  ''|[123].*|4.[012].*) echo "ERROR: bash 4.3+ required" >&2; exit 1;;
esac

# store Python code in a string
expand_py=$(cat <<'EOF'
try:
  import sys, glob, braceexpand
except ImportError as e:
  sys.stderr.write("Did you remember to install the braceexpand Python module?\n")
  raise e

for arg in sys.argv[1:]:
  for globexp in braceexpand.braceexpand(arg):
    glob_results = glob.glob(globexp)
    if len(glob_results) == 0:
      sys.stdout.write(globexp)
      sys.stdout.write('\0')
      continue
    else:
      sys.stdout.write(''.join(['%s\0' % result for result in glob_results]))
EOF
)

# shell wrapper for the above Python program
expand() {
  local item
  local -n dest_array=$1; shift

  dest_array=( )
  while IFS= read -r -d '' item; do
    dest_array+=( "$item" )
  done < <(python3 -c "$expand_py" "$@")
  unset -n dest_array
}

# actually demonstrate usage
expand yourArray '{a,b}{1,2}'
declare -p yourArray
declare -a yourArray=([0]="a1" [1]="a2" [2]="b1" [3]="b2")