sh:如果命令只包含字母,数字和下划线,将变量用作命令是否安全?

时间:2018-04-05 17:51:21

标签: shell dash-shell

我正在破折号中编写符合POSIX标准的脚本,因此我必须使用虚假阵列发挥创意。

fake_array.sh的内容

fake_array_job() {
array="$1"
job_name="$2"

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"运行功能有任何负面影响,因为它涉及稳定性,安全性或效率?

1 个答案:

答案 0 :(得分:1)

(阅读最后查看Charles Duffy提出的一个好建议。我太懒了,不能完全改写我之前提到它的答案......)

你可以迭代"数组"使用简单的参数扩展而不需要数组中的多个元素。

fake_array_job() {
    args=${1%,},   # Ensure the array ends with a comma
    job_name=$2

    while [ -n "$args" ]; do
        item=${args%%,*}
        "$job_name" || exit
        args=${args#*,}
    done 
}

上面的一个问题是通过假设foo,bar,不是带有空的最后一个元素的逗号分隔数组来确保数组以逗号结尾。一个更好(虽然更丑陋)的解决方案是使用read来分解数组。

fake_array_job () {
  args=$1
  job_name=$2
  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