将 $REPLY 设置为函数 arg 不起作用

将 $REPLY 设置为函数 arg 不起作用

我决定为验证 while 循环创建 fn ,我将在整个代码中重复使用它:

loopFN() {
   while true; do
      if [ "$1" == "null" ] || ([ "$2" == "phone number" ] && ! [[ "$1" =~ $phone_regex ]]); then
         printf 'enter a valid %s\n' "$2"
         read
         $1=$REPLY
      else
         break
      fi  
   done
}

我这样称呼它:

   local number="null"
   loopFN "$number" "phone number"

我的电话号码正则表达式是:

phone_regex="^[0-9]{3}-[0-9]{3}-[0-9]{4}"

我得到的错误是:

./newmenu.sh: line 27: null=dasd: command not found

其中“dasd”是我在提示时输入的内容

重用 while 循环是不好的做法吗?我应该重写它多少次吗?或者我的语法有问题吗?

我猜问题就在这里(错误引用的第 27 行):

     $1=$REPLY

我试图设置传入 fn 的变量,在本例中为 $number,我最初的想法是它不起作用,因为 var 是本地的,但我删除了 local 关键字,错误仍然存​​在

编辑:

我根据建议添加了一些更改:

loopFN() {
   while true; do
      if [[ $1 = null ]]; then
         printf>&2 'enter a valid %s\n' "$2"
         IFS= read -r "$1"
      elif [[ $1 = null || ( $2 = 'phone number' && ! $1 =~ $phone_regex ) ]]; then
         printf>&2 "enter a valid phone number\n"
         IFS= read -r "$1"
      else
         break
      fi  
   done
}

答案1

$1=$REPLY=不被理解为变量赋值,因为( )的左边$1不是有效的变量名,因此它仅被视为命令参数或命令参数列表(因为$1并且$REPLY未加引号,所以受 split+glob 的约束)它被视为命令名称。

你需要:

eval "$1=\$REPLY"

要要求 shellcontents_of_$1=$REPLY作为 shell 代码进行计算,并假设 的内容$1是有效的变量名称,则会将 的值分配$REPLY给相应的变量(如果$1reboot;foo,则显然会重新启动)。

在这里你还可以这样做:

IFS= read -r "$1"

它将使用作为参数read的内容进行调用,并且不关心也无法知道该变量名是按字面传递还是扩展的结果。$1read

这仍然是一个命令注入漏洞(就像when $1is一样foo[`reboot`])。

无论如何,读取一行的语法是IFS= read -r line, 不是read line

另请注意(...),在 Korn 风格[[...]]构造之外启动一个子 shell,您的

if [ "$1" == "null" ] || ([ "$2" == "phone number" ] && ! [[ "$1" =~ $phone_regex ]])

更应该是:

if [[ $1 = null || ( $2 = 'phone number' && ! $1 =~ $phone_regex ) ]]

如果$1是一个变量名,那就$1 =~ $phone_regex没什么意义了。电话号码很少是有效的变量名称。

如果您打算检查名称为 的变量的内容$1,那么您可以使用${!1}bash 语法来取消引用变量,或者按照 ChatGPT 的建议,将 ksh93 样式的名称引用与较新版本的 bash 一起使用。

请注意,无论如何,您需要传递给函数的是变量名称 ( number) 而不是值 ( )。$number

用户提示和交互通常会转到 stderr,stdout 被保留用于命令产生的实际输出,其他东西可能想要重用/后处理。

printf>&2 'enter a valid %s\n' "$2"

特别是对于bashshell,您可以使用-pread内置选项来发出prompt(它也会发送到 stderr):

IFS= read -rp "Enter a valid $2: " "$1"

而在大多数其他类似 Korn 的 shell 中,语法是:

IFS= read -r "$1?Enter a valid $2: "

如果该函数旨在输入电话号码,反复询问直到用户输入有效的电话号码,并将其返回到第一个参数中提供名称的变量中,然后使用 bash 特定的语法,它看起来像:

input_phone_number() {
  local -n _var_name="$1"
  local _regex='^[0123456789]{3}-[0123456789]{3}-[0123456789]{4,}$'
  until
    IFS= read -rp 'Please enter a valid phone number: ' _var_name ||
      return # return failure upon EOF
    [[ $_var_name =~ $_regex ]]
  do
    echo>&2 'Not a valid phone number, try again.'
  done
}

input_phone_number number || exit

(使用[0123456789]而不是[0-9]as[0-9]可以匹配任何内容,并在末尾和开头锚定正则表达式)。

对于input采用输入类型和验证正则表达式作为参数的通用函数:

input() {
  local -n _var_name="$1"
  local _type="$2" _regex="$3"
  until
    IFS= read -rp "Please enter a valid $_type: " _var_name ||
      return # return failure upon EOF
    [[ $_var_name =~ $_regex ]]
  do
    echo>&2 "Not a valid $_type, try again."
  done
}

input number \
      'phone number' \
      '^[0123456789]{3}-[0123456789]{3}-[0123456789]{4,}$' || exit

请注意_局部变量中的前缀,以便用户可以执行input type type '^(good|bad)$'例如操作,而不会导致$type局部变量与他们想要返回的用户$type变量发生冲突。

相关内容