$ 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がローカルなので、うまくいかないと思いましたが、ローカルキーワードを削除しましたが、エラーは続行されます。

編集する:

提案に基づいていくつかの変更を追加しました。

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符がないため、分割+globに適用されます)。コマンドとして扱われます。

以下を行う必要があります。

eval "$1=\$REPLY"

シェルにcontents_of_$1=$REPLYシェルコードで評価するように要求し、その内容が有効な変数名であると仮定すると、その値がその変数に割り当て$1られます(そうであれば明らかに再開されます)。$REPLY$1reboot;foo

ここで次のこともできます。

IFS= read -r "$1"

引数として使用されているものを使用して呼び出され、read変数名が文字通り渡されるか拡張の結果であるかは関係ありません。$1read

これはまだコマンドインジェクションの脆弱性です(例:when $1is foo[`reboot`])。

とにかく、一行を読む構文はIFS= read -r line、そうではありませんかread line

また、 Korn スタイル(...)の構成外でサブシェルを起動するには[[...]]

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

それ以上でなければなりません:

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

$1変数名であれば意味$1 =~ $phone_regexがないでしょう。電話番号は有効な変数名ではないことがよくあります。

という変数の内容を調べたい場合は、bash構文を使用して変数を逆参照するか、ChatGPTで推奨されているように、最新バージョンのbashでksh93スタイル名の引用を使用できます$1${!1}

いずれにせよ、number関数に渡す必要があるのは値()ではなく変数名()です。$number

ユーザープロンプトとのやり取りは通常stderrに移動し、stdoutはコマンドで生成された実際の出力と再利用/後処理をしたい他の項目のために予約されています。

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

特にbashシェルの場合、組み込みオプションを使用してromptを実行できます-preadstderrpにも送信されます)。

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

他のほとんどのKorn様シェルでは、構文は次のとおりです。

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

(asの[0123456789]代わりに使用して何かを一致させ、終わりと始めに正規表現を固定します)。[0-9][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

おすすめ記事