저는 많은 문제를 해결하는 쉘 애플리케이션을 만들고 있으며 이를 read -p "<my_question>" <myvar>
여러 번 사용해 왔습니다. 문제는 대답이 비어 있는지도 확인하고 싶다는 것입니다. 그래서 비어 있는지 묻고 확인하는 일반 함수를 만들고 싶습니다. 그렇다면 사용자가 무언가를 제공할 때까지 함수 자체가 재귀적으로 호출됩니다. 변수 이름을 "userdatabase"로 "수정"하면 모든 것이 완벽하게 실행됩니다. 함수 선언 및 사용법을 따르십시오.
ask() {
read -p "$1" $2
if [[ -z $userdatabase ]]; then
echo Empty is not allowed
ask "$1" $2
else
echo $userdatabase
fi
}
ask "Provides the user database: " userdatabase
물론 나는 응용 프로그램이 묻는 모든 질문에 대한 변수 이름으로 "userdatabase"를 사용하고 싶지 않습니다. 그래서 나는 "동적" 변수가 필요하다는 것을 깨달았습니다. 사고를 좀 더 역동적으로 만들면 다음과 같습니다.
ask() {
read -p "$1" $2
if [[ -z $$var ]]; then
echo Empty is not allowed
ask "$1" $2
else
echo $$var
fi
}
ask "Provides the user database: " $var
하지만 유틸리티를 사용하면 SOMENUMBERvar와 같은 메시지가 나타납니다. 분명히 나는 쉘에서 "동적 변수"를 올바른 방식으로 사용하지 않는 것 같습니다.
그렇다면 질문문을 수신하는 함수와 명령의 변수로 채워질 변수 이름을 어떻게 생성합니까 read -p
?
답변1
가장 간단한 경우부터 시작하세요. 함수를 만드세요:
f() { read -p "Type smthng: " $1 ; }
함수 호출 및 변수 할당$p입력을 저장한 다음 입력을 표시합니다. 뒤쪽에기능 종료:
f p ; echo $p
"woof"를 입력하라는 메시지가 표시되고 echo $p
동일한 내용이 출력됩니다.
Type smthng: woof
woof
변수를 확인하는 한 가지 방법은 함수를 다른 함수로 래핑하는 것입니다.
g() { unset $1 ; until f "$1" && eval [ \"\$"$1"\" ] ; do echo wrong ; done ; }
까다로운 부분은 OP가 변수 이름을 함수 매개변수로 할당하려고 한다는 것입니다."사악한"eval
분석하다. 변수 전달이름함수 인수는 거의 수행되거나 필요하지 않지만 이를 수행하는 한 가지 방법을 보여줍니다.
테스트를 받아보세요:
g p ; echo $p
메시지가 나타나면 을 클릭하면 Enter오류 메시지가 인쇄되고 두 번째 프롬프트에 "foo"를 입력합니다.
Type smthng:
wrong
Type smthng: foo
foo
OP 코드의 이 부분은 작동하지 않습니다.
if [[ -z $$var ]]; then
이는 현재 PID를 반환하는 변수 $$
입니다 .bash
man bash | grep -A 28 "Special Parameters$" | sed -n '1,3p;28,$p'
Special Parameters
The shell treats several parameters specially. These parameters may only
be referenced; assignment to them is not allowed.
$ Expands to the process ID of the shell. In a () subshell, it expands
to the process ID of the current shell, not the subshell.
답변2
ask() {
# $1 ---> message to user
# $2 ---> "VARIABLE NAME" in which read will store response
case ${2-} in
'' | *[!a-zA-Z0-9_]* | [0-9]* )
echo >&2 "Oops you've selected an invalid variable name: \`$2'"
exit 1;;
esac
read -p "$1" "$2"
eval "
case \${$2:++} in
'' )
echo >&2 'Empty response not allowed.'
ask '$1' '$2';;
* )
echo \"\${$2}\";;
esac
"
}
VarName=${1-'humpty_dumpty'}
ask "Provide the user database: " "$VarName"
답변3
최근에 발견한 내용을 공유하고 싶었습니다. 답변 유효성 검사에 추가 단계를 추가하려고 시도했습니다. 또한 경로가 존재하는지 확인했지만 이에 대해 Rakesh Sharma의 솔루션을 적용할 수 없었습니다. 마침내 내가 찾던 것을 찾았는데, 그것은 "동적 변수"를 다루는 방법이었고 실제 방법은 ${!var}를 사용하는 것이었다. 내 함수의 최종 버전과 사용법은 다음과 같습니다.
ask_validate() {
read -p "$1" $2
if [ -z ${!2} ]; then
echo Empty answer is not allowed.
ask_validate "$1" $2
return
fi
if ! [ -d ${!2} ]; then
echo You need to provides an existing path
ask_validate "$1" $2
return
fi
echo The var name is: $2
echo The var value is: ${!2}
}
ask_validate "Please, provides the host path: " host_path
ask_validate "Please, provides the virtual host configuration path: " virtualhost_path
echo The host path is $host_path
echo The virtual host configuration path is $virtualhost_path
답변4
그래서 비어 있는지 묻고 확인하는 일반 함수를 만들고 싶습니다.
이것은 좋은 생각일 수 있습니다.
그렇다면 사용자가 무언가를 제공할 때까지 함수 자체가 재귀적으로 호출됩니다.
이건...좋은 생각이 아닙니다. 루프를 사용하십시오.
함수형 프로그래밍 언어에서는 단순한 루프 대신 재귀를 사용하는 것이 일반적일 수 있지만 쉘의 경우는 그렇지 않고 아마도 그다지 똑똑하지도 않기 때문에 테일 호출을 최적화할 가능성이 적습니다. 반대로 재귀가 깊어지면 메모리 사용량이 더 많아집니다. 여기서는 그렇게 많은 반복을 수행하지 않기 때문에 문제가 되지 않을 수 있지만 일반적으로 트리와 같은 데이터 구조를 탐색할 때와 같이 필요할 때만 재귀를 사용하는 것이 좋습니다.
또는 변수 이름을 함수에 인수로 전달하는 대신 기본 프로그램에서 할당을 수행할 수 있습니다.
ask() {
read -p "$1: " a
while [ -z "$a" ] ; do
echo "Please give a value" >&2
read -p "$1: " a
done
echo "$a"
}
var=$(ask "please enter some value")
echo "you gave $var"
물론, stdout이 변수에 할당되었으므로 이제 경고를 stderr로 리디렉션해야 합니다. 이는 read
프롬프트의 역할이기도 합니다. 예를 들어 간접 참조를 dash
지원하지 않는 것 같습니다 .${!x}