[英]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.