使用数组动态分配变量名,然后提取数组数据同时避免eval
Use an array to dynamically assign a variable name, then extract array data while avoiding eval
我正在重写一个主要脚本。部分原因是出于人们可能避免使用 eval 的常见原因而删除了 eval。我 运行 找不到管理以下场景类型的可行方法。
考虑这两个 eval 语句:
eval echo '${'#${role}'[@]}' users
loc_NagiosUsersAll+=($( eval echo '${'${role}'[@]}' " " ))
第一个打印以筛选给定角色中的用户数。第二个将所有这些用户添加到一个更大的数组中。
角色是当前正在评估的角色恰好是什么。我们称它为 read_only。我们可以这样写第一个语句:
printf "${#read_only[@]} users"
我已经尝试了数十种括号、引号和各种杂技的组合来放弃 eval 并使它们起作用。
这里是echo echo版本(使用其中一个实际角色)进行对比:
$ echo echo '${'#${role}'[@]}' users
echo ${#authorized_for_all_host_commands[@]} users
$ echo ${#authorized_for_all_host_commands[@]} users
6 users
$ eval echo '${'#${role}'[@]}' users
6 users
我已经设法放弃了所有其他 eval 语句,但这种类型像滴答声一样深入人心。
那么,我怎样才能比使用 eval 更安全呢?
更多代码...
declare -a NagiosUserRolesAll=( authorized_for_read_only
authorized_for_all_services
authorized_for_all_hosts
authorized_for_system_information
authorized_for_configuration_information
authorized_for_system_commands
authorized_for_all_service_commands
authorized_for_all_host_commands )
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_NagiosUsersAll=""
printf "Loading users into the different tables. \n"
for role in "${NagiosUserRolesAll[@]}"
do
declare -ag $role="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${role} has ${#ref[@]} users. \n"
loc_NagiosUsersAll+=(${ref[@]})
loc_NagiosUsersAll+=" "
done
printf "Creating list of unique users. \n"
NagiosUsersAllClean=($( echo ${loc_NagiosUsersAll[@]} | tr ' ' '\n' |
sort -u ))
printf "Total users: ${#NagiosUsersAllClean[@]}. \n"
}
function func_NagiosUsersShow(){ # was show_all_users
if [[ "${svnFileExists}" == '1' ]] ; then
printf "You'll need to checkout a cgi.cfg file first. \n"
return 1
fi
printf "\nThese are the roles with their users. \n\n"
for role in "${NagiosUserRolesAll[@]}"
do
# declare -ng ref="${role}" # copy the reference, not the contents of the array
printf "These users are in ${const_TextRed}${role}"
printf "${const_TextPlain}: "
printf "${const_TextGreen}"
# printf "${ref[@]} \n" # FAILS
printf "${ref[*]} \n" # ALSO FAILS (prints one user for each role)
# eval echo '${'${role}'[@]}' # WORKS
printf "${const_TextPlain} \n"
done
printf "\nNow for a list of unique users. \n\n"
func_EnterToContinue
printf "Unique users list: \n"
for i in "${!NagiosUsersAllClean[@]}"
do
printf "$i: ${NagiosUsersAllClean[$i]} \n"
done
func_EnterToContinue
}
使用 bash 4.3 或更高版本,您可以通过说 declare -n varref
将一个变量声明为对另一个变量的引用。这是一个示例代码:
#!/bin/bash
declare -a read_only=(Alice Bob Charlie)
declare -a authorized_for_all_host_commands=(Dan Emma Fred George Harry Irene)
declare -a loc_NagiosUsersAll
declare -n role="read_only"
echo ${#role[@]} users
# yields "3 users"
loc_NagiosUsersAll+=(${role[@]})
declare -n role="authorized_for_all_host_commands"
echo ${#role[@]} users
# yields "6 users"
loc_NagiosUsersAll+=(${role[@]})
echo ${#loc_NagiosUsersAll[@]} users
# yields "9 users"
echo ${loc_NagiosUsersAll[@]}
# yields "Alice Bob Charlie Dan Emma Fred George Harry Irene"
希望这对您有所帮助。
[已编辑]
以下代码是根据你最新的post.
修改后的版本
declare -a NagiosUserRolesAll=( authorized_for_read_only
authorized_for_all_services
authorized_for_all_hosts
authorized_for_system_information
authorized_for_configuration_information
authorized_for_system_commands
authorized_for_all_service_commands
authorized_for_all_host_commands )
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_CaptureUsersPerRole=""
local -a loc_NagiosUsersAll=""
printf "Loading users into the different tables. \n"
for role in "${NagiosUserRolesAll[@]}"; do
declare -a $role="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
printf "These users have the role ${role}: "
declare -n ref=$role # copy the reference, not the contents of the array
printf "${#ref[@]} users \n"
loc_NagiosUsersAll+=(${ref[@]})
# loc_NagiosUsersAll+=" "
done
printf "Creating list of unique users. \n"
NagiosUsersAllClean=($( echo ${loc_NagiosUsersAll[@]} | tr ' ' '\n' | sort -u ))
printf "Total users: ${#NagiosUsersAllClean[@]}. \n"
}
[5 月 12 日编辑]
关键是对引用的赋值应该出现在 declare -n
语法中。否则会产生意想不到的结果。这是示例:
declare -a arys=(ary_a ary_b ary_c)
declare -a ary_a=(a1 a2 a3)
declare -a ary_b=(b1 b2 b3)
declare -a ary_c=(c1 c2 c3)
# test 1
for role in "${arys[@]}"; do
declare -n ref="$role"
echo "${ref[@]}"
done
# => works properly
# test 2
for role in "${arys[@]}"; do
declare -n ref
ref="$role"
echo "${ref[@]}"
done
# => does not work correctly
[5 月 15 日编辑]
这是应该工作的修改版本:
declare -a NagiosUserRolesAll=( authorized_for_read_only
authorized_for_all_services
authorized_for_all_hosts
authorized_for_system_information
authorized_for_configuration_information
authorized_for_system_commands
authorized_for_all_service_commands
authorized_for_all_host_commands )
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_NagiosUsersAll=""
printf "Loading users into the different tables. \n"
for role in "${NagiosUserRolesAll[@]}"
do
declare -ag $role="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${role} has ${#ref[@]} users. \n"
loc_NagiosUsersAll+=(${ref[@]})
loc_NagiosUsersAll+=" "
done
printf "Creating list of unique users. \n"
NagiosUsersAllClean=($( echo ${loc_NagiosUsersAll[@]} | tr ' ' '\n' |
sort -u ))
printf "Total users: ${#NagiosUsersAllClean[@]}. \n"
}
function func_NagiosUsersShow(){ # was show_all_users
if [[ "${svnFileExists}" == '1' ]] ; then
printf "You'll need to checkout a cgi.cfg file first. \n"
return 1
fi
printf "\nThese are the roles with their users. \n\n"
for role in "${NagiosUserRolesAll[@]}"
do
declare -ng ref="${role}" # copy the reference, not the contents of the array
printf "These users are in ${const_TextRed}${role}"
printf "${const_TextPlain}: "
printf "${const_TextGreen}"
# printf "${ref[@]} \n" # FAILS
printf "${ref[*]} \n" # => should work
# eval echo '${'${role}'[@]}' # WORKS
printf "${const_TextPlain} \n"
done
printf "\nNow for a list of unique users. \n\n"
func_EnterToContinue
printf "Unique users list: \n"
for i in "${!NagiosUsersAllClean[@]}"
do
printf "$i: ${NagiosUsersAllClean[$i]} \n"
done
func_EnterToContinue
}
两个函数的最终工作版本如下。我不清楚为什么 printf 行需要那种精确的格式,但你已经知道了。
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_NagiosUsersAll=""
printf '%s\n' "Loading users into the different tables. "
for role in "${NagiosUserRolesAll[@]}"
do
declare -ag "${role}"="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${role} has ${#ref[@]} users. %s\n"
loc_NagiosUsersAll+=("${ref[@]}")
loc_NagiosUsersAll+=(" ")
done
printf '%s\n' "Creating list of unique users. "
NagiosUsersAllClean=($( echo "${loc_NagiosUsersAll[@]}" | tr ' ' '\n' | sort -u ))
printf "There are ${#NagiosUsersAllClean[@]} total users. %s\n"
}
function func_NagiosUsersShow(){ # was show_all_users
if [[ "${svnFileExists}" == '1' ]] ; then
printf '%s\n' "You'll need to checkout a cgi.cfg file first. "
return 1
fi
printf '%s\n' "" "These are the roles with their users. " ""
for role in "${NagiosUserRolesAll[@]}"
do
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${const_TextRed}${role}${const_TextPlain} has these ${#ref[@]} users: %s"
printf "${const_TextGreen} %s\n"
printf '%s ' "${ref[@]} "
printf "${const_TextPlain} %s\n"
printf "%s\n"
done
read -p "Now, would you like to see a list of unique users? (y/N) "
if func_YesOrNo "${REPLY}"
then
printf '%s\n' "Unique users list: "
for i in "${!NagiosUsersAllClean[@]}"
do
printf "$i: ${NagiosUsersAllClean[$i]} %s\n"
done
func_EnterToContinue
else
return 0
fi
}
我正在重写一个主要脚本。部分原因是出于人们可能避免使用 eval 的常见原因而删除了 eval。我 运行 找不到管理以下场景类型的可行方法。
考虑这两个 eval 语句:
eval echo '${'#${role}'[@]}' users
loc_NagiosUsersAll+=($( eval echo '${'${role}'[@]}' " " ))
第一个打印以筛选给定角色中的用户数。第二个将所有这些用户添加到一个更大的数组中。
角色是当前正在评估的角色恰好是什么。我们称它为 read_only。我们可以这样写第一个语句:
printf "${#read_only[@]} users"
我已经尝试了数十种括号、引号和各种杂技的组合来放弃 eval 并使它们起作用。
这里是echo echo版本(使用其中一个实际角色)进行对比:
$ echo echo '${'#${role}'[@]}' users
echo ${#authorized_for_all_host_commands[@]} users
$ echo ${#authorized_for_all_host_commands[@]} users
6 users
$ eval echo '${'#${role}'[@]}' users
6 users
我已经设法放弃了所有其他 eval 语句,但这种类型像滴答声一样深入人心。
那么,我怎样才能比使用 eval 更安全呢?
更多代码...
declare -a NagiosUserRolesAll=( authorized_for_read_only
authorized_for_all_services
authorized_for_all_hosts
authorized_for_system_information
authorized_for_configuration_information
authorized_for_system_commands
authorized_for_all_service_commands
authorized_for_all_host_commands )
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_NagiosUsersAll=""
printf "Loading users into the different tables. \n"
for role in "${NagiosUserRolesAll[@]}"
do
declare -ag $role="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${role} has ${#ref[@]} users. \n"
loc_NagiosUsersAll+=(${ref[@]})
loc_NagiosUsersAll+=" "
done
printf "Creating list of unique users. \n"
NagiosUsersAllClean=($( echo ${loc_NagiosUsersAll[@]} | tr ' ' '\n' |
sort -u ))
printf "Total users: ${#NagiosUsersAllClean[@]}. \n"
}
function func_NagiosUsersShow(){ # was show_all_users
if [[ "${svnFileExists}" == '1' ]] ; then
printf "You'll need to checkout a cgi.cfg file first. \n"
return 1
fi
printf "\nThese are the roles with their users. \n\n"
for role in "${NagiosUserRolesAll[@]}"
do
# declare -ng ref="${role}" # copy the reference, not the contents of the array
printf "These users are in ${const_TextRed}${role}"
printf "${const_TextPlain}: "
printf "${const_TextGreen}"
# printf "${ref[@]} \n" # FAILS
printf "${ref[*]} \n" # ALSO FAILS (prints one user for each role)
# eval echo '${'${role}'[@]}' # WORKS
printf "${const_TextPlain} \n"
done
printf "\nNow for a list of unique users. \n\n"
func_EnterToContinue
printf "Unique users list: \n"
for i in "${!NagiosUsersAllClean[@]}"
do
printf "$i: ${NagiosUsersAllClean[$i]} \n"
done
func_EnterToContinue
}
使用 bash 4.3 或更高版本,您可以通过说 declare -n varref
将一个变量声明为对另一个变量的引用。这是一个示例代码:
#!/bin/bash
declare -a read_only=(Alice Bob Charlie)
declare -a authorized_for_all_host_commands=(Dan Emma Fred George Harry Irene)
declare -a loc_NagiosUsersAll
declare -n role="read_only"
echo ${#role[@]} users
# yields "3 users"
loc_NagiosUsersAll+=(${role[@]})
declare -n role="authorized_for_all_host_commands"
echo ${#role[@]} users
# yields "6 users"
loc_NagiosUsersAll+=(${role[@]})
echo ${#loc_NagiosUsersAll[@]} users
# yields "9 users"
echo ${loc_NagiosUsersAll[@]}
# yields "Alice Bob Charlie Dan Emma Fred George Harry Irene"
希望这对您有所帮助。
[已编辑] 以下代码是根据你最新的post.
修改后的版本declare -a NagiosUserRolesAll=( authorized_for_read_only
authorized_for_all_services
authorized_for_all_hosts
authorized_for_system_information
authorized_for_configuration_information
authorized_for_system_commands
authorized_for_all_service_commands
authorized_for_all_host_commands )
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_CaptureUsersPerRole=""
local -a loc_NagiosUsersAll=""
printf "Loading users into the different tables. \n"
for role in "${NagiosUserRolesAll[@]}"; do
declare -a $role="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
printf "These users have the role ${role}: "
declare -n ref=$role # copy the reference, not the contents of the array
printf "${#ref[@]} users \n"
loc_NagiosUsersAll+=(${ref[@]})
# loc_NagiosUsersAll+=" "
done
printf "Creating list of unique users. \n"
NagiosUsersAllClean=($( echo ${loc_NagiosUsersAll[@]} | tr ' ' '\n' | sort -u ))
printf "Total users: ${#NagiosUsersAllClean[@]}. \n"
}
[5 月 12 日编辑]
关键是对引用的赋值应该出现在 declare -n
语法中。否则会产生意想不到的结果。这是示例:
declare -a arys=(ary_a ary_b ary_c)
declare -a ary_a=(a1 a2 a3)
declare -a ary_b=(b1 b2 b3)
declare -a ary_c=(c1 c2 c3)
# test 1
for role in "${arys[@]}"; do
declare -n ref="$role"
echo "${ref[@]}"
done
# => works properly
# test 2
for role in "${arys[@]}"; do
declare -n ref
ref="$role"
echo "${ref[@]}"
done
# => does not work correctly
[5 月 15 日编辑] 这是应该工作的修改版本:
declare -a NagiosUserRolesAll=( authorized_for_read_only
authorized_for_all_services
authorized_for_all_hosts
authorized_for_system_information
authorized_for_configuration_information
authorized_for_system_commands
authorized_for_all_service_commands
authorized_for_all_host_commands )
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_NagiosUsersAll=""
printf "Loading users into the different tables. \n"
for role in "${NagiosUserRolesAll[@]}"
do
declare -ag $role="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${role} has ${#ref[@]} users. \n"
loc_NagiosUsersAll+=(${ref[@]})
loc_NagiosUsersAll+=" "
done
printf "Creating list of unique users. \n"
NagiosUsersAllClean=($( echo ${loc_NagiosUsersAll[@]} | tr ' ' '\n' |
sort -u ))
printf "Total users: ${#NagiosUsersAllClean[@]}. \n"
}
function func_NagiosUsersShow(){ # was show_all_users
if [[ "${svnFileExists}" == '1' ]] ; then
printf "You'll need to checkout a cgi.cfg file first. \n"
return 1
fi
printf "\nThese are the roles with their users. \n\n"
for role in "${NagiosUserRolesAll[@]}"
do
declare -ng ref="${role}" # copy the reference, not the contents of the array
printf "These users are in ${const_TextRed}${role}"
printf "${const_TextPlain}: "
printf "${const_TextGreen}"
# printf "${ref[@]} \n" # FAILS
printf "${ref[*]} \n" # => should work
# eval echo '${'${role}'[@]}' # WORKS
printf "${const_TextPlain} \n"
done
printf "\nNow for a list of unique users. \n\n"
func_EnterToContinue
printf "Unique users list: \n"
for i in "${!NagiosUsersAllClean[@]}"
do
printf "$i: ${NagiosUsersAllClean[$i]} \n"
done
func_EnterToContinue
}
两个函数的最终工作版本如下。我不清楚为什么 printf 行需要那种精确的格式,但你已经知道了。
function func_NagiosUserDataGet(){ # was load_data_tables
local -a loc_NagiosUsersAll=""
printf '%s\n' "Loading users into the different tables. "
for role in "${NagiosUserRolesAll[@]}"
do
declare -ag "${role}"="($( cat ${svnFilePath} | sed -n "s/${role}=//p" | sed 's/,/ /g' ))"
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${role} has ${#ref[@]} users. %s\n"
loc_NagiosUsersAll+=("${ref[@]}")
loc_NagiosUsersAll+=(" ")
done
printf '%s\n' "Creating list of unique users. "
NagiosUsersAllClean=($( echo "${loc_NagiosUsersAll[@]}" | tr ' ' '\n' | sort -u ))
printf "There are ${#NagiosUsersAllClean[@]} total users. %s\n"
}
function func_NagiosUsersShow(){ # was show_all_users
if [[ "${svnFileExists}" == '1' ]] ; then
printf '%s\n' "You'll need to checkout a cgi.cfg file first. "
return 1
fi
printf '%s\n' "" "These are the roles with their users. " ""
for role in "${NagiosUserRolesAll[@]}"
do
declare -n ref="${role}" # copy the reference, not the contents of the array
printf "The role ${const_TextRed}${role}${const_TextPlain} has these ${#ref[@]} users: %s"
printf "${const_TextGreen} %s\n"
printf '%s ' "${ref[@]} "
printf "${const_TextPlain} %s\n"
printf "%s\n"
done
read -p "Now, would you like to see a list of unique users? (y/N) "
if func_YesOrNo "${REPLY}"
then
printf '%s\n' "Unique users list: "
for i in "${!NagiosUsersAllClean[@]}"
do
printf "$i: ${NagiosUsersAllClean[$i]} %s\n"
done
func_EnterToContinue
else
return 0
fi
}