sh: 如果命令仅包含字母、数字和下划线,那么将变量用作命令是否安全?
sh: Is it safe to use a variable as a command if the command contains only letters, number and underscores?
我正在用 dash 编写一个 POSIX 兼容的脚本,所以我必须通过使用假数组来发挥创意。
fake_array.sh
的内容
fake_array_job() {
array=""
job_name=""
comma_count="$(echo "$array" | grep -o -F ',' | wc -l)"
if [ "$comma_count" -lt '1' ]; then
echo 'You gave a fake array to fake_array_job that does not contain at least one comma. Exiting...'
exit
fi
array_count="$(( comma_count + 1 ))"
position=1
while [ "$position" -le "$array_count" ]; do
item="$(echo "$array" | cut -d ',' -f "$position")"
"$job_name" || exit
position="$(( position + 1 ))"
done
}
script.sh
的内容
#!/bin/sh
. fake_array.sh
job_to_do() {
echo "$item"
}
fake_array_job 'goat,pig,sheep' 'job_to_do'
second_job() {
echo "$item"
}
fake_array_job 'apple,orange' 'second_job'
我知道为我传递给 fake_array_job 的每个作业使用唯一的名称可能看起来很愚蠢,但我喜欢我必须输入两次,因为它有助于减少人为错误。
我一直在读到将变量用作命令是个坏主意。我对 运行 函数使用“$job_name”是否有任何负面影响,因为它涉及稳定性、安全性或效率?
(读到最后,Charles Duffy 提出了一个很好的建议。我懒得完全重写我的答案以提早提...)
您可以使用简单的参数扩展遍历 "array",而不需要数组中有多个元素。
fake_array_job() {
args=${1%,}, # Ensure the array ends with a comma
job_name=
while [ -n "$args" ]; do
item=${args%%,*}
"$job_name" || exit
args=${args#*,}
done
}
上面的一个问题是,通过假设 foo,bar,
不是最后一个元素为空的 comma-delimited 数组来确保数组是 comma-terminated。更好(虽然更难看)的解决方案是使用 read
来分解数组。
fake_array_job () {
args=
job_name=
rest=$args
while [ -n "$rest" ]; do
IFS=, read -r item rest <<EOF
$rest
EOF
"$job_name" || exit
done
}
(您可以使用 <<-EOF
并确保此处的文档使用 制表符 缩进,但很难在此处表达,所以我将保留丑陋的版本。)
还有 Charles Duffy 的好建议,使用 case
对数组进行模式匹配,看看是否还有逗号:
while [ -n "$args" ]; do
case $var in
*,*) next=${args%%,*}; var=${args#*,}; "$cmd" "$next";;
*) "$cmd" "$var"; break;;
esac;
done
我正在用 dash 编写一个 POSIX 兼容的脚本,所以我必须通过使用假数组来发挥创意。
fake_array.sh
的内容fake_array_job() {
array=""
job_name=""
comma_count="$(echo "$array" | grep -o -F ',' | wc -l)"
if [ "$comma_count" -lt '1' ]; then
echo 'You gave a fake array to fake_array_job that does not contain at least one comma. Exiting...'
exit
fi
array_count="$(( comma_count + 1 ))"
position=1
while [ "$position" -le "$array_count" ]; do
item="$(echo "$array" | cut -d ',' -f "$position")"
"$job_name" || exit
position="$(( position + 1 ))"
done
}
script.sh
的内容#!/bin/sh
. fake_array.sh
job_to_do() {
echo "$item"
}
fake_array_job 'goat,pig,sheep' 'job_to_do'
second_job() {
echo "$item"
}
fake_array_job 'apple,orange' 'second_job'
我知道为我传递给 fake_array_job 的每个作业使用唯一的名称可能看起来很愚蠢,但我喜欢我必须输入两次,因为它有助于减少人为错误。
我一直在读到将变量用作命令是个坏主意。我对 运行 函数使用“$job_name”是否有任何负面影响,因为它涉及稳定性、安全性或效率?
(读到最后,Charles Duffy 提出了一个很好的建议。我懒得完全重写我的答案以提早提...)
您可以使用简单的参数扩展遍历 "array",而不需要数组中有多个元素。
fake_array_job() {
args=${1%,}, # Ensure the array ends with a comma
job_name=
while [ -n "$args" ]; do
item=${args%%,*}
"$job_name" || exit
args=${args#*,}
done
}
上面的一个问题是,通过假设 foo,bar,
不是最后一个元素为空的 comma-delimited 数组来确保数组是 comma-terminated。更好(虽然更难看)的解决方案是使用 read
来分解数组。
fake_array_job () {
args=
job_name=
rest=$args
while [ -n "$rest" ]; do
IFS=, read -r item rest <<EOF
$rest
EOF
"$job_name" || exit
done
}
(您可以使用 <<-EOF
并确保此处的文档使用 制表符 缩进,但很难在此处表达,所以我将保留丑陋的版本。)
还有 Charles Duffy 的好建议,使用 case
对数组进行模式匹配,看看是否还有逗号:
while [ -n "$args" ]; do
case $var in
*,*) next=${args%%,*}; var=${args#*,}; "$cmd" "$next";;
*) "$cmd" "$var"; break;;
esac;
done