将参数中的变量更改为bash函数

时间:2017-12-20 21:26:40

标签: bash function unix

在我的bash脚本中,我经常提示用户提供y / n答案。因为我经常在一个脚本中多次使用它,所以我想要一个函数来检查用户输入是否为Yes / No的变体,然后将此答案清除为“y”或“n”。像这样:

yesno(){
    temp=""
    if [[ "$1" =~ ^([Yy](es|ES)?|[Nn][Oo]?)$ ]] ; then
        temp=$(echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/es//g' | sed 's/no//g')
        break
    else
        echo "$1 is not a valid answer."
    fi
}

然后我想使用如下函数:

while read -p "Do you want to do this? " confirm; do # Here the user types "YES"
    yesno $confirm
done
if [[ $confirm == "y" ]]; then
    [do something]
fi

基本上,我想将第一个参数的值更改为$confirm的值,这样当我退出yesno函数时,$confirm是“y”或“ N”。

我尝试在set -- "$temp"函数中使用yesno,但我无法让它工作。

2 个答案:

答案 0 :(得分:1)

您可以通过输出新值并覆盖调用者中的变量来实现。

yesno() {
    if [[ "$1" =~ ^([Yy](es|ES)?|[Nn][Oo]?)$ ]] ; then
        local answer=${1,,}
        echo "${answer::1}"
    else
        echo "$1 is not a valid answer." >&2
        echo "$1"  # output the original value
        return 1   # indicate failure in case the caller cares
    fi
}

confirm=$(yesno "$confirm")

但是,我建议采用更直接的方法:让函数执行提示和循环。将所有重复的逻辑移到里面。然后呼叫站点非常简单。

confirm() {
    local prompt=$1
    local reply

    while true; do
        read -p "$prompt" reply

        case ${reply,,} in
            y*) return 0;;
            n*) return 1;;
            *)  echo "$reply is not a valid answer." >&2;;
        esac
    done
}

if confirm "Do you want to do this? "; then
    # Do it.
else
    # Don't do it.
fi

${reply,,}是一种将$reply转换为小写的bash-ism。)

答案 1 :(得分:1)

您可以使用Bash的 nameref 属性(需要Bash 4.3或更高版本),如下所示:

#!/bin/bash

yesno () {
    # Declare arg as reference to argument provided
    declare -n arg=$1

    local re1='(y)(es)?'
    local re2='(n)o?'

    # Set to empty and return if no regex matches
    [[ ${arg,,} =~ $re1 ]] || [[ ${arg,,} =~ $re2 ]] || { arg= && return; }

    # Assign "y" or "n" to reference
    arg=${BASH_REMATCH[1]}
}

while read -p "Prompt: " confirm; do
    yesno confirm
    echo "$confirm"
done

示例测试运行如下:

Prompt: YES
y
Prompt: nOoOoOo
n
Prompt: abc

Prompt: 

表达式锚定在开头,因此yessss等也都计算在内。如果不需要,可以添加结束锚($)。

如果两个表达式都不匹配,则将字符串设置为空。