如何填充传递给bash脚本的变量,该变量是从另一个bash脚本调用的?我想知道选项和最佳实践。
让我详细说明为什么通过设置退出状态或echo
来回答的许多问题是不够的:
exit n
:n被限制为0< = n< = 255 echo foo
不允许我回显该脚本中的任何相关信息,备用屏幕缓冲区也不会对此有所帮助。我找到了一个可能的解决方案:
#outer.sh
source inner.sh
populate result
echo "Evaluated: $result"
#inner.sh
function populate {
local __popvar=$1
eval $__popvar="'RETURN VALUE'"
}
我不喜欢这个解决方案有三个原因:
source
内部脚本,使用辅助函数污染全局范围。eval
,特别是因为混淆的多引号。bash inner.sh result
。内部脚本应该写入备用屏幕缓冲区。在此缓冲区上,用户可以从阵列中选择一个选项(通过箭头键或ijkl样式选择,使用空格确认或输入)。应该以某种方式从脚本返回此选项。返回索引不是一个选项,因为数组中的元素数量可能超过256.代码:
#!/usr/bin/bash
prompt=$1; shift
options=( "$@" )
c_opts=${#options[@]}
selected=0
# switch to alternate screen and trap the kill signal to switch back
tput smcup
trap ctrl_c INT
function ctrl_c {
tput rmcup
exit 1
}
function print_opts {
for (( i = 0; i < $c_opts; i++ )); do
if [[ i -eq $selected ]]; then
echo -e "\t\e[7m ${options[i]} \e[0m"
else
echo -e "\t ${options[i]} "
fi
done
}
function reset_term {
for (( i = 0; i < $c_opts; i++ )); do
tput cuu1 # move cursor up 1 line
tput el # delete current line
done
}
function reprint_opts {
reset_term
print_opts
}
echo $prompt
print_opts
while read -sN1 key; do
read -sN1 -t 0.0001 k1
read -sN1 -t 0.0001 k2
read -sN1 -t 0.0001 k3
key+="${k1}${k2}${k3}"
# colemak layout
case "$key" in
n|u|$'\e[A'|$'\e0A'|$'\e[D'|$'\e0D') # up or left
((selected > 0)) && ((selected--));;
e|i|$'\e[B'|$'\e0B'|$'\e[C'|$'\e0C') # down or right
((selected < $c_opts-1)) && ((selected++));;
$'\e[1~'|$'\e0H'|$'\e[H') # home key
selected=0;;
$'\e[4~'|$'\e0F'|$'\e[F') # end key
((selected = $c_opts-1));;
' '|$'\x0a') # enter or space
tput rmcup && echo ${options[$selected]} && exit 0;;
q|$'\e') # q or escape
tput rmcup && exit 0;;
esac
reprint_opts
done
基于@ JohnKugelman的评论,该脚本应按以下方式调用:
prompt="Your options are:"
options=(
"Option A"
"Option B"
"Option C"
"Option D"
)
result=$( exec 3>&1; bash select-menu.sh "$prompt" "${options[@]}" 2>&1 1>&3; exec 3>&- )
echo $result
这似乎是一个吸引人的解决方案,但它无法解决问题。不打印要在备用屏幕缓冲区上打印的“选择”菜单。但输入正常,选择存储在result
。
要了解所需的行为,您可以替换调用脚本中的最后两行,如下所示:
bash select-menu.sh "$prompt" "${options[@]}"
答案 0 :(得分:3)
不要排除result=$(inner.sh)
。如果要在脚本中显示交互式提示或对话框,请在stderr上执行这些操作,并让它只写入stdout的答案。然后你可以吃蛋糕并吃掉它:交互式提示和将结果保存到变量中。
例如,如果您使用dialog
告诉它将其答案写入stdout,则--output-fd 1
会执行此操作。它使用curses将对话框绘制到备用屏幕,但在stderr上完成所有操作。
$ value=$(dialog --keep-tite --output-fd 1 --inputbox title 10 40)
<dialog box shown>
<type "hello">
hello
(通过Ask Ubuntu: How to get dialog box input directed to a variable?)
您发布的脚本可以做同样的事情。它目前写入stdout。将exec 3>&1 1>&2
放在顶部,这样它就会写入stderr,并将最终echo ${options[$selected]}
更改为echo ${options[$selected]} >&3
以将答案写入stdout。这样就不需要调用者来处理文件描述符了。
那说,提示不是很UNIX-y。考虑完全避开交互性以支持命令行参数,配置文件或环境变量。对于知道如何使用脚本并希望自行自动化的高级用户来说,这些选项更好。
我的主要目的是从我上次备份的选择中提交
latest-stable-config
,我认为这需要人们判断何时将备份视为适当稳定。
我个人处理的方式是编写一个带有几种模式的脚本。我们称之为backups
。 backups --list
将显示备份列表。你选择一个,然后调用backups --commit <id>
,它将提交命名配置。没有参数的backups
将显示不熟悉用户的使用情况。
$ backups
Usage: backups --list
or: backups --commit <id>
Manages a selection of backups. Use --list to list available backups
and --commit to commit the latest stable config.
$ backups --list
4ac6 10 minutes ago
18f2 1 day ago
3019 7 days ago
$ backups --commit 4ac6