私はコード全体で再利用する検証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
$1
reboot;foo
ここで次のこともできます。
IFS= read -r "$1"
引数として使用されているものを使用して呼び出され、read
変数名が文字通り渡されるか拡張の結果であるかは関係ありません。$1
read
これはまだコマンドインジェクションの脆弱性です(例:when $1
is 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を実行できます-p
(read
stderrp
にも送信されます)。
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