我有这个shell脚本,我想修改它以确保它在Bash环境中正确运行。
这是脚本:
#!/bin/zsh
# Some constants. The first two will become env variables.
UPDATE_DNS_API_HOST="https://example.com"
UPDATE_DNS_API_URL="$UPDATE_DNS_API_HOST/my_end_point"
CURRENT_PUBLIC_IP=$(curl -s "$UPDATE_DNS_API_URL" | grep -o '".*"' | tr -d '"')
if [[ $PUBLIC_IP == $CURRENT_PUBLIC_IP ]]; then
echo "Current IP: "$CURRENT_PUBLIC_IP" already set."
else
response=$(curl -s -H "Content-Type: application/json" \
--data "$CURRENT_PUBLIC_IP" "$UPDATE_DNS_API_URL")
echo $response
export PUBLIC_IP="$CURRENT_PUBLIC_IP"
fi
以下是我的问题:
#!/bin/bash
欢迎任何其他反馈。
答案 0 :(得分:1)
如果您希望有人调用script.sh
在bash
而不是zsh
下运行,那么您必须修复shebang。
内部双引号:
echo "Current IP: "$CURRENT_PUBLIC_IP" already set."
是非正统的,不是个好主意。使用:
echo "Current IP: $CURRENT_PUBLIC_IP already set."
你可能想要双引号:
echo "$response"
否则,我认为你没问题。至于资源,您可以查看Bash manual,或使用shellcheck.com等设施,或咨询Bash FAQ。
如果您使用[[ … ]]
,您可能会写好。 shell语法的常规规则在[[ … ]]
中暂停,并且让那些学习Bourne shell的人感到困惑,并且不会费心去学习Bash的那部分。
您必须点(. script.sh
)或源(source script.sh
)export PUBLIC_IP="$CURRENT_PUBLIC_IP"
的脚本才能对调用shell产生任何影响。否则,它会设置运行脚本的shell环境,但不会影响调用shell。
如果您确定要使用带有dot命令的脚本,那么您应该考虑在设置完成之前应该设置多少个变量。也许它们是否在它们开始之前被设置了。创建一个函数,除了要导出的变量之外,所有变量都声明为local,这样可以简化生活。当脚本作为单独的进程运行时,您不必担心这一点。
答案 1 :(得分:1)
这里需要记住的一件事是UNIX进程可以为自己和未来的孩子修改环境变量 - 不他们的父母,没有父进程直接参与。
如果你的意图是在封闭shell中设置一个变量,一种相当常见的方法是在stdout上发出shell命令。这意味着任何不是 shell命令的东西都应该移动到stderr(无论如何这都是合适的做法,因为stderr被指定为适用于信息文本和状态内容)。
此版本确实需要bash,而不是/bin/sh
,但是使用printf '%q'
来确保它能够以eval
生成变量名称 - 所有ksh派生的安全方式(ksh) ,bash,zsh)应该能够阅读。
#!/bin/bash
# note that while this runs with bash, ksh and zsh will also be able to eval its output
# ...POSIX sh too, when there aren't nonprintable characters causing $''-style quoting
# ...to be used.
# usage: emit_cmd varname ...
#
# emit code that defines a variable when evaluated on stdout
emit_cmd() {
for varname; do
printf 'export %q=%q; ' "$varname" "${!varname}"
done
}
# Some constants. The first two will become env variables.
UPDATE_DNS_API_HOST="https://example.com"
UPDATE_DNS_API_URL="$UPDATE_DNS_API_HOST/my_end_point"
# print definitions of those variables to stdout
emit_cmd UPDATE_DNS_API_HOST UPDATE_DNS_API_URL
CURRENT_PUBLIC_IP=$(curl -s "$UPDATE_DNS_API_URL" | grep -o '".*"' | tr -d '"')
if [[ $PUBLIC_IP = $CURRENT_PUBLIC_IP ]]; then
echo "Current IP: $CURRENT_PUBLIC_IP already set." >&2
else
response=$(curl -s -H "Content-Type: application/json" \
--data "$CURRENT_PUBLIC_IP" "$UPDATE_DNS_API_URL")
echo "$response" >&2
PUBLIC_IP="$CURRENT_PUBLIC_IP" emit_cmd PUBLIC_IP
fi
如果此脚本以名称ip-lookup
保存,则可以使用以下命令将其定义的变量导入当前shell:
eval "$(ip-lookup)"
使用此约定可保持与需要修改环境变量的ssh-agent
等现有UNIX工具的兼容性。
请注意,我保留了有关变量名称的现有约定,但如果有机会,则应切换到小写名称以符合relevant POSIX convention。