繁体   English   中英

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

[英]Expand curly braces and wildcards in a bash string variable (without eval)

给定bash中的一个字符串变量(不是字符串),如何展开它的花括号(并将任何文件通配符如星号通配),然后将展开的结果存储在一个数组中?

我知道这可以通过eval实现:

#!/usr/bin/env bash

string="{a,b}{1,2}"
array=( $( eval echo $string ) )
echo "${array[@]}"
#a1 a2 b1 b2

但是如果我们不信任string的内容(比如,如果它是脚本的参数), eval可能是危险的。 嵌入分号、引号、空格、任意命令等的string可以打开脚本进行攻击。

bash有没有更安全的方法做这个扩展? 我怀疑以下所有扩展字符串的方式同样不安全

#!/usr/bin/env bash

eval echo $string

bash <<< "echo $string"

echo echo $string | bash

bash <(echo echo $string)

除了 bash 之外,是否还有其他命令可以将 pipe 字符串发送到该命令以进行扩展?

旁白:请注意,在csh/tcsh中这很容易,因为大括号扩展发生变量替换之后(与 bash 不同):

#!/usr/bin/env csh

set string = "{a,b}{1,2}"
set array = ( $string )
echo "$array"
#a1 a2 b1 b2

braceexpand Python 模块与标准库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

...运行预期数组值时的输出:

declare -a yourArray=([0]="a1" [1]="a2" [2]="b1" [3]="b2")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM