Linux 서버에 여러 패키지를 설치하고 구성하는 자동화된 bash 스크립트를 작성 중입니다.
여러 서버에서 이 스크립트를 재사용하고 싶지만 필요에 따라 일부 매개변수를 변경합니다. 이렇게 하면 나중에 찾기 및 바꾸기를 사용하여 여러 변경 사항을 적용하여 많은 코드를 실행할 필요가 없습니다. 스크립트의 상단/시작 부분에 해당 값을 정의할 수 있으므로 스크립트 전체에서 변수를 사용합니다.
일부 변수는 비밀번호이므로 일반 텍스트 파일에 비밀번호를 저장하는 것을 피하고 싶습니다. 내 해결 방법은 변수 값을 읽을 수 있는 암호화된 문서에 저장한 다음 스크립트 시작 부분에서 변수를 정의하는 것이었습니다. 일련의 질문을 실행하고 변수 값을 설정하기 위한 입력을 요청하면 됩니다. 다음 명령을 사용하여 이 작업을 수행하는 방법을 알아냈습니다.
read -p "`echo -e 'Enter admin user password: \n\b'`" admin_user_password
echo "You entered '$admin_user_password"
Bash 스크립팅에서 더 까다로운 부분은 스크립트가 진행되어 자동으로 자체 작업을 수행하기 전에 모든 변수가 설정되어 있는지(공백으로 두지 않음) 올바르게 입력되었는지 확인하고 싶다는 것입니다. 처음에 변수를 설정하는 것은 사용자 상호 작용이 필요한 스크립트의 유일한 부분입니다. 그것이 작동하도록 하려면 루프를 조사할 것이라고 확신합니다.
이것은 스크립트의 자동 부분이 시작되기 전에 루프를 실행하려는 순서입니다.
- 스크립트는 사용자에게 입력을 요청하여 변수를 요청합니다.
- 사용자가 설정한 변수는 전체 변수 목록과 비교하여 확인됩니다. 1단계에서 입력/설정되지 않은 변수는 "$some-variable에 대한 값을 설정하지 않았습니다."라는 나머지 질문과 함께 사용자에게 경고합니다.
- 모든 변수가 설정되면 설정된 모든 변수와 해당 값을 인쇄하고 간단한 예/아니요로 올바른지 묻습니다. 만약 정확하지 않다면 다시 1단계로 돌아가서 문제를 해결하고 싶습니다. 그러나 변수와 값이 올바르면 스크립트는 자동화 부분으로 계속 진행됩니다.
이것이 내가 지금까지 가지고 있는 것입니다.
## TOP OF SCRIPT ##
script_variables=(
admin_user_name
admin_user_password
)
for i in "${script_variables[@]}"; do
read -p "`echo -e 'Enter value for: \n\b'`" ${script_variables[@]}
echo "You entered '${script_variables[@]}'"
if test -z "${script_variables[@]}"
then
echo "${script_variables[@]} has not been set"
# loopback to the top of the script
continue
else
while true; do
read -p "Are the variables ccorrect?" yn
case $yn in
[Yy]* ) echo "All variables have been set. The script will now continue."; sleep 2; break;;
[Nn]* ) continue;;
* ) echo "Please answer yes or no.";;
esac
fi
done
# Automated script commands below
위의 명령이 작동하는지 잘 모르겠습니다. where is line 14를 수행하더라도 continue
루프는 ## TOP OF SCRIPT ## 섹션으로 돌아가서 배열의 모든 질문을 다시 묻습니다. 두 번째로 질문을 하면 변수가 설정되었는지 자체적으로 확인해야 합니다. 이것은 아직 설정되지 않은 변수에 대해 다시 묻는 유일한 질문입니다.
내가 할 수 있는 유일한 방법은 변수 테스트 부분을 처음에 넣는 것입니다. 이는 변수 설정에 대해 처음 질문을 받을 때 아직 변수가 설정되지 않았다는 메시지를 받게 된다는 의미입니다.
제가 도움을 요청하는 이유는 제가 루프를 거의 다루지 않기 때문입니다. 내 Unix 지식은 대부분 독학으로 이루어졌으며 주로 이와 같은 포럼에서 인터넷을 탐색하거나 가상 환경에서 Linux PC에서 명령을 시도하여 이루어졌으며 아직 루프에 너무 깊이 들어가지는 않았습니다. 루프를 사용할 때마다 인터넷에서 가져와 내 스크립트에 사용하는 조각입니다. 분명히 위의 스크립트에서는 중첩된 루프를 살펴보고 있으며 이는 더욱 복잡해집니다.
업데이트 1
귀하의 훌륭한 답변과 관련하여 변수를 입력하면 아래의 새 줄에 입력되도록 표시되는 텍스트를 조정하고 싶습니다.
예를 들어, 어떻게 해야 하나요?
read -p ("Enter value for $varName \n\b " script_variables[$varName]
나는 다음과 같은 것을 표시하고 싶습니다 :
Enter value for admin_user_name
>
인터넷에서 가이드를 보고 이용할 수 있었어요 echo -e
. \n\b
나는 그것을 가지고 놀았지만 변수는 확장되지 않았습니다.
https://stackoverflow.com/questions/8467424/echo-newline-in-bash-prints-literal-n
업데이트 2
저는 스크립트를 확장하고 임시 파일에서 변수를 읽고 저장하는 선택적 방법을 구현할 생각입니다. 적절한 Unix 권한을 설정하여 다른 시스템 사용자를 보호할 수 있으며 스크립트 끝에서 파일을 삭제하여 흔적이 남지 않도록 할 것입니다.
스크립트 시작 부분에서 변수가 포함된 특정 텍스트 파일이 있는지 확인하고 싶습니다. 파일이 존재하는 경우 모든 변수가 설정되었는지 확인하고 변수 이름 배열과 비교하십시오. 파일에 저장된 변수가 불완전한 경우 변수가 설정될 때까지 루프가 실행됩니다. 분명히 파일에 저장된 변수는 사용자가 "이것이 맞습니까?"라는 질문에 "예"라고 대답한 경우에만 설정됩니다.
이 스크립트가 작동하게 되면 GitHub에 게시하고 내 답변을 최종 버전으로 업데이트하여 다른 사람들이 사용할 수 있도록 하고 싶습니다. 이는 확실히 다른 사람들에게 도움이 될 것이기 때문입니다.
답변1
좋습니다. 먼저 몇 가지 분명한 질문을 드리겠습니다. ${script_variables[@]}
공백으로 구분된 전체 배열 로 확장됩니다 . 따라서 스크립트 시작 부분에서 배열을 정의할 때 항상 오류가 표시되므로 $script_variables
결코 비어 있지 않습니다. 배열의 요소를 참조하려면 첫 번째 요소, 두 번째 요소 등 특정 숫자 인덱스를 사용해야 합니다.test -z "${script_variables[@]}"
"${script_variables[@]}"
"${script_variables[0]}"
"${script_variables[1]}"
read
둘째, 변수에 값을 저장할 때는 해당 값을 변수에 저장해야 합니다. 그러나 귀하가 제공한 확장된 배열은 read
배열에 저장된 값일 뿐입니다.
$ echo "${script_variables[@]}"
admin_user_name admin_user_password
더 중요한 것은 사용자가 지정한 값을 이름으로 호출할 수 있는 변수에 저장하려는 것 같습니다. 이것은 당신이 설정한 값 var="foo"
이고, variableName="var"
가져오려고 시도하는 값입니다.바꾸다이름 지정 var
(이 경우 "foo")을 "간접 확장"이라고 합니다. 예를 들면 다음과 같습니다 ${!variableName}
.
$ var="foo"
$ variableName="var"
$ echo "${!variableName}"
foo
따라서 이를 사용할 수도 있고 두 개의 배열을 사용할 수도 있습니다. 하나는 변수 이름을 저장하고 다른 하나는 해당 값을 저장합니다. 또는 최신 버전의 bash의 경우 단일을 사용하는 것이 더 좋습니다.연관 배열해당 키는 변수 이름이 됩니다. 다음은 간접 확장을 사용하는 스크립트의 작업 버전입니다.
#/bin/bash
script_variables=(
admin_user_name
admin_user_password
)
## This will be used to exit the loop
allSet="";
while [[ -z $allSet ]]; do
for varName in "${script_variables[@]}"; do
## No need to loop the whole thing, just loop
## until this particular variable has been set
while [[ -z ${!varName} ]]; do
read -p "Enter value for $varName: " $varName
done
done
## We will only exit the loop once all vars have been set.
## Now print and check them.
printf '\n=========\nYou have entered:\n'
for varName in "${script_variables[@]}"; do
printf '%s=%s\n' "$varName" "${!varName}"
done
while true; do
read -p "Are the variables correct? " yn
case $yn in
[Yy]* )
echo "All variables have been set. The script will now continue.";
## Setting this to 1 exits the top "while [[ -z $allSet ]]; do" loop
allSet=1
break;;
[Nn]* )
## Clear the stored values to start again
for varName in "${script_variables[@]}"; do
unset $varName
done
break;;
* )
echo "Please answer yes or no.";;
esac
done
done
연관 배열을 사용하는 버전은 다음과 같습니다.
#/bin/bash
declare -A script_variables=(
[admin_user_name]=""
[admin_user_password]=""
)
## This will be used to exit the loop
allSet="";
while [[ -z $allSet ]]; do
## '${!array[@]}' returns all keys of an associative array
for varName in "${!script_variables[@]}"; do
read -p "Enter value for $varName: " script_variables[$varName]
done
## We will only exit the loop once all vars have been set.
## Now print and check them.
printf '\n=========\nYou have entered:\n'
for varName in "${!script_variables[@]}"; do
printf '%s=%s\n' "$varName" "${script_variables[$varName]}"
done
while true; do
read -p "Are the variables correct? " yn
case $yn in
[Yy]* )
echo "All variables have been set. The script will now continue.";
## Setting this to 1 exits the top "while [[ -z $allSet ]]; do" loop
allSet=1
break;;
[Nn]* )
## Clear the stored values to start again
for varName in "${!script_variables[@]}"; do
script_variables[$varName]=""
done
break;;
* )
echo "Please answer yes or no.";;
esac
done
done
이제 개인적으로 저는 약간 다른 접근 방식을 사용하겠습니다. 모든 것을 설정한 다음 사용자가 마지막에 확인하도록 하는 대신, 입력할 때 모든 것을 확인하겠습니다. 이렇게 하면 처음에 오류가 발생하고 모든 변수를 재설정할 필요 없이 오류가 발생한 변수만 재설정할 수 있습니다. 이 같은:
#/bin/bash
declare -A script_variables=(
[admin_user_name]=""
[admin_user_password]=""
)
allSet=0;
while [[ $allSet -lt ${#script_variables[@]} ]]; do
for varName in "${!script_variables[@]}"; do
ok=""
while [[ $ok != [Yy]* ]]; do
read -p "Enter value for $varName: " script_variables[$varName]
read -p "You entered '${script_variables[$varName]}'. Is this correct? " ok
done
## If we're satisfied, increment the value of allSet
((allSet++))
done
done
## You can add a second test here, but just exit the script if it's wrong.
## There's no point in complicating your code if you're just going back to
## the beginning anyway: just exit and rerun it.
printf '\n=========\nYou have entered:\n'
for varName in "${!script_variables[@]}"; do
printf '%s=%s\n' "$varName" "${script_variables[$varName]}"
done
read -p "Is everything OK? (y/n; n will exit the script)": yn
if [[ $yn != [Yy]* ]]; then
exit
fi
echo "Everything correctly set, continuing!"