스크립트가 있습니다. 내가 하고 싶은 일은
- 특정 명령이 실패하는 경우(조건 불일치는 실패로 간주되지 않음)
- 일부 명령이 실패하는 경우에만 스크립트는 실패한 명령을 일시 중지하고 사용자에게 표시하고 사용자에게 명령을 편집할지 묻습니다.
- 사용자가 "y"를 입력하면 해당 명령이 vim에서 열리며, 여기서 사용자는 잘못된 명령을 편집하고 새 명령으로 스크립트를 복원하게 됩니다.
- 또는 사용자가 "n"을 입력하면 일반적으로 다음 명령을 계속합니다.
위의 방법을 개발해야합니다
지금까지 나는 다음과 같은 메커니즘을 추론했습니다.
trap rerun ERR
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
#위의 내용을 사용하면 각 명령을 이전 명령 변수에 저장할 수 있습니다. 따라서 명령이 실패하면 이전 명령 변수를 사용하여 해당 명령 문자열을 가져올 수 있습니다.
rerun() {
echo "$previous_command" | vim -
#OR vim <(echo "$previous_command")
}
이전 명령을 vim에 반영하고 사용자가 이를 편집하고 실행할 수 있도록 하는 방법을 원합니다.
[
simple way: echo previous command >> tmpfile
vi tmpfile
#now user will edit it and save and exit
then
eval "$(cat tmpfile)"
]
하지만 저는 ctrl+x ctrl+e를 사용하여 프로그래밍 방식으로 임시 파일이 아닌 파일 없는 솔루션을 원합니다.
주요 요점
우리는 다시 실행할 수 있습니다
rerun() {
echo "$previous_command" | vim -
#OR vim <(echo "$previous_command")
}
현재 쉘 컨텍스트에서 편집 후 실행하는 방법 또한 함수를 다시 실행한 후 명령이 두 번째로 실패하는 경우 오류가 포착되지 않아야 합니다.다음 명령을 계속 실행하고 실패한 명령을 기록합니다.
아마도 fc 명령이 편집 및 실행에 도움이 될 수 있습니다.
지금까지 제가 추론한 내용은 다음과 같습니다. 쉘 스크립트 시작 부분에 다음을 추가하십시오.
rerun() {
printf "%s\n" "Below Command Failed:" "$previous_command"
read -p "Do You Want to Continue execution or edit the failed command.(Y/N)" input
if [[ "$input" =~ (y|Y) ]]; then { fc -e vi -1; }; elif [[ -z "$input" ]] || [[ "$input" =~ (n|N) ]]; then :; fi
}
trap rerun ERR
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
하지만 위의 내용은 테스트하지 않았습니다. 더 강력한 솔루션을 환영합니다.
또한 명령이 실패할 때 트랩에 의해 재실행이 수행되는 메커니즘을 구현하고 싶습니다. 하지만 재실행 후에도 명령이 두 번째로 실패하면 재실행하지 말고 다음 명령을 계속 진행하세요.
위의 문제에 대해 나는 다음을 시도했습니다.
rerun() {
if [[ -n "$norepeat" ]]; then unset norepeat
elif [[ -z "$norepeat" ]]; then
printf "%s\n" "Below Command Failed:" "$previous_command"
read -p "Do You Want to Continue execution or edit the failed command.(Y/N)" input
if [[ "$input" =~ (y|Y) ]]; then { fc -e vi -1; [[ "$?" != "0" ]] && norepeat=1; }; elif [[ -z "$input" ]] || [[ "$input" =~ (n|N) ]]; then norepeat=1; fi
}
trap rerun ERR
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
설명하다: 처음 오류가 발생하면 재실행이 수행되고 사용자에게 계속할지 아니면 편집하고 실행할지 묻는 메시지가 표시됩니다. "Y" 프롬프트에서는 fc 명령을 사용하여 마지막 명령을 실행하고 실행된 명령이 상태 0으로 종료되지 않았는지 테스트합니다. 즉, 명령이 두 번째 실패했기 때문에 norepeat=1로 설정됩니다. 오류로 인해 실패 시 재실행이 다시 실행됩니다. 하지만 이번에는 norepeat가 설정되어 있으므로 fc는 실행되지 않지만 norepeat는 설정 해제되고 스크립트는 다음 명령을 계속 실행하게 됩니다. 이제 다른 명령이 실패하면 rerun이 호출되지만 norepeat가 설정 해제되었으므로 fc 명령이 실행됩니다.
위의 내용은 테스트되지 않았습니다. $ 뒤의 fc 명령이 확실하지 않습니까? 실제로 fc 명령을 테스트하거나 다시 실행된 명령의 종료 코드를 다시 편집합니다.
내 접근 방식과 기타 강력한 솔루션에 대한 비판과 개선을 환영합니다. 도와주세요.
또 다른 필요한 것은 두 번째 실패 시 명령을 failed.log에 기록하는 것입니다.#두 번째 실패 시 이전_명령이 "fc commamd"로 설정될지 아니면 "재실행된 명령"으로 설정될지 확실하지 않기 때문입니다.
위에 대한 제안: 재실행 기능 내에서 $LINENO
첫 번째 명령을 캡처할 수 있으며 norepeat 후에 fc 명령을 설정한 후 아래와 같이 할 수 있습니다 echo "$LINENO" >> failed.log
( sed ''"$LINENO"'p' -En "$0" >> failed.log
작동하는지 확실하지 않음).
rerun() {
failed_lineno="$LINENO"
if [[ -n "$norepeat" ]]; then unset norepeat
elif [[ -z "$norepeat" ]]; then
printf "%s\n" "Below Command Failed:" "$previous_command"
read -p "Do You Want to Continue execution or edit the failed command.(Y/N)" input
if [[ "$input" =~ (y|Y) ]]; then { fc -e vi -1; [[ "$?" != "0" ]] && { norepeat=1; sed ''"$failed_lineno"'p' -En "$0" >> failed.log; }; elif [[ -z "$input" ]] || [[ "$input" =~ (n|N) ]]; then norepeat=1; fi
}
trap rerun ERR
trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
답변1
제 생각에는 이것은 완전히 잘못된 접근 방식입니다. 편집 명령이 현재 작업과 관련이 없으면 어떻게 됩니까? 사용자가 vim에서 "실패한 명령"을 열고 점심 먹으러 갔다가 작업을 잊어버리면 어떻게 되나요? 편집된 명령 자체가 실패하고 사용자가 그 이유를 모르는 경우에는 어떻게 됩니까?
복잡한 작업이 있고 일부 단계가 실패할 것으로 예상되는 경우. 예를 들어, 여러 모듈로 구성되어 있고 다양한 하드웨어/운영 체제를 수용하기 위해 즉시 조정해야 하는 복잡한 애플리케이션을 설치할 수 있습니다. 이러한 작업은 일반적으로 여러 메뉴를 통해 해결되며, 각 주요 단계(다운로드할 모듈, 다운로드할 미러 등)는 다음과 같이 구성됩니다.
# make a menu function
choose_modules() {
echo -ne "
a) Use module A
b) Use module B
c) Use module C
z) done"
read a
case $a in
a) use_module_a=yes ; choose_modules;;
b) use_module_b=yes ; choose_modules;;
c) use_module_c=yes ; choose_modules;;
z) exit 0 ;;
*) echo "Wrong option" ; choose_modules;;
esac
}
# the main script starts with a forever loop
while true
do
use_module_a=no
use_module_b=no
use_module_c=no
choose_modules
if [ $use_module_a = "yes" ] ; then
# some commands for this option
fi
if [ $use_module_b = "yes" ] ; then
# some commands for this option
fi
if [ $use_module_c = "yes" ] ; then
# some commands for this option
fi
# at the end of the loop, ensure that we have at least one module,
# if yes - exit the loop, if not a single module installed - restart the loop
if [ $have_module_a=yes -o $have_module_b=yes -o $have_module_c=yes ] ; then
break
fi
done
사용자가 내릴 수 있는 중요한 결정에 대해 이와 같은 메뉴를 제공할 수 있습니다.