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

将参数中命名的变量更改为bash函数,bash,function,unix,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' |

在我的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
}
Prompt: YES
y
Prompt: nOoOoOo
n
Prompt: abc

Prompt: 
然后,我想使用以下函数:

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
#!/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
基本上,我想将第一个参数的值更改为
$confirm
的值,这样当我退出
yesno
函数时,
$confirm
要么是“y”要么是“n”


我尝试在
yesno
函数中使用
set--“$temp”
,但无法使其工作。

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

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。)

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

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
#!/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
示例测试运行如下所示:

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
}
Prompt: YES
y
Prompt: nOoOoOo
n
Prompt: abc

Prompt: 
表达式锚定在开始处,因此
yesss
等。所有表达式也都计算在内。如果不需要,可以添加端锚(
$


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

这似乎是一个X-Y问题——问题是关于建议的解决方案,而不是OP实际想要使用该解决方案解决的问题。被接受的答案在外部范围内根本不会改变,
“$1”
,因此其他人将其作为搜索结果查找时可能会感到困惑——也许应该对问题进行编辑,以便更紧密地描述真实/直接的问题?…也就是说,基于原始标题,我原以为OP想知道如何更改
$1
本身,而不是
$1
内容中命名的变量的值。为了将来参考,应该注意
${reply,,}
仅在Bash 4或newer@HubertL艾维尔·高文:谢谢你的提示。你知道如何用bash 3明智地完成吗?