![如何以正确的方式从 bash 函数返回?](https://linux22.com/image/216584/%E5%A6%82%E4%BD%95%E4%BB%A5%E6%AD%A3%E7%A1%AE%E7%9A%84%E6%96%B9%E5%BC%8F%E4%BB%8E%20bash%20%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%EF%BC%9F.png)
我在终端中获取的这个脚本提供了_cphetzner
用于创建 git 存储库的函数。该函数使用另一个_feed_variable
提示用户缺少变量的函数。
此时我的问题是:
- 这是从函数返回的正确方法吗 - 使用
return 1
? - 如果
set -o errexit
未注释,脚本是否会在任何return 1
(例如,从函数_feed_variable
或仅返回到 shell 的函数)上中止? - 如果
set -o errexit
未注释,那么在不关闭终端的情况下退出函数的正确方法是什么? - 我觉得我没有以清除错误的方式设计脚本。有什么建议吗?
#!/usr/bin/env bash
# +---------------+
# | Bash settings |
# +---------------+
# abort on nonzero exitstatus
# set -o errexit
# abort on unbound variable
# set -o nounset
# don't hide errors within pipes
# set -o pipefail
# +----------------+
# | Bash Variables |
# +----------------+
# +----------------+
# | Script Content |
# +----------------+
function _feed_variable() {
local prompt_msg=$1
local var_to_set=$2
echo "$prompt_msg"
read answer
case $answer in
[Yy]*)
echo "Enter $2: "
read new_value
eval $var_to_set="'$new_value'"
return 0
;;
[Nn]*)
echo "Clearing up and quitting ..."
return 1
;;
esac
}
function _cphetzner() {
pushd $PWD > /dev/null
POSITIONAL_ARGS=()
REPO_NAME=
# TARGET_FOLDER=$PWD/$REPO_NAME
TARGET_FOLDER=
SOURCE_TEMPLATE=
while [[ $# -gt 0 ]]; do
case $1 in
-r|--repository)
REPO_NAME="$2"
shift
shift
;;
-s|--sourcetemplate)
SOURCE_TEMPLATE="$2"
shift
shift
;;
-t|--targetfolder)
TARGET_FOLDER="$2"
shift
shift
;;
-*|--*)
echo "Unknown option $1"
exit 1
;;
*)
POSITIONAL_ARGS+=("$1") # save positional arg
shift # past argument
;;
esac
done
#=====[ Print Info ]==================================
echo "SOURCE_TEMPLATE is:\t" $SOURCE_TEMPLATE
echo "TARGET_FOLDER is:\t" $TARGET_FOLDER
echo "{POSITIONAL_ARGS is [@]}:\t" ${POSITIONAL_ARGS[@]}
echo "REPO_NAME is:\t" $REPO_NAME
set -- "${POSITIONAL_ARGS[@]}"
if [[ -n $1 ]]; then
echo "Last line of file specified as non-opt/last argument:"
tail -1 "$1"
fi
#=====[ Create folder and initiate repository ]=======
# Check if user input has repo name
if [[ -z "$REPO_NAME" ]]; then
_feed_variable "Do you want to feed me a repository name? [y/n]" "REPO_NAME" ||
return 1
fi
# Check if repository in given path exists
if [[ -z "$TARGET_FOLDER" ]]; then
_feed_variable "Do you want to feed me a target name? [y/n]" "TARGET_FOLDER" ||
return 1
fi
while [[ -d "${TARGET_FOLDER}/${REPO_NAME}" ]]
do
echo "Repository already exist in this folder" &&
_feed_variable "Do you want to feed me another target name? [y/n]" "TARGET_FOLDER" ||
return 1
done
# Create folder
mkdir -p $TARGET_FOLDER/$REPO_NAME
# # Check if template folder exists
# [[ -z $SOURCE_TEMPLATE ]] && echo "No template folder" ||
# cp -a $SOURCE_TEMPLATE/ $TARGET_FOLDER/$REPO_NAME
#====[ Initiate Repo ]================================
cd $TARGET_FOLDER/$REPO_NAME
git init
git remote add origin hetzner:/yolo/$REPO_NAME.git
git add .
git commit -m "Initial commit"
echo -e "[DONE] Repo $REPO_NAME created successfully"
echo -ne "Do you want to push repo to Hetzner now? [y/n]"
read answer
case $answer in
[Yy]*)
echo "Pushing to Hetzner ..."
git push -u -f origin master
;;
[Nn]*)
;;
esac
echo "Have a great day ..."
return 0
popd > /dev/null
}
答案1
shell 认为退出状态为零真实/成功,并且非零状态为虚假/失败。因此,如果该功能成功,return 0
则可能会被认为比 更正确return 1
。
至于set -e
/ set -o errexit
,它不会在任何命令/函数上触发,例如,它会忽略那些用作条件或退出状态被忽略的命令/函数,例如管道的非最右侧部分。不过,发生故障的嵌套级别并不重要。但它确实存在一些复杂性,使其难以使用。
fail() { return 1; }
# these won't trigger set -e
fail | cat
fail || true
if fail; then echo x; fi
# so this prints
echo one
# these also won't trigger it
try() {
fail
echo two
}
try || true
( fail; echo three ) || true
看https://mywiki.wooledge.org/BashFAQ/105对于 的怪事set -e
。