在bash字符串变量中展开大括号和通配符(不带eval)
给定bash中的字符串变量(不是字符串),如何展开它的大括号(并对任何文件通配符(如星号)进行全局化),然后将结果展开存储在数组中 我知道这可以通过在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可能是危险的(比如,如果它是脚本的参
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
!Tryarr=({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")