나는 코드 전체에서 재사용할 검증 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
stderr p
에도 전송됨).
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