Case 문을 사용하여 UNIX에서 상세 모드를 켜고 끄는 방법

Case 문을 사용하여 UNIX에서 상세 모드를 켜고 끄는 방법

getopts를 사용하여 쉘 스크립트 파일을 생성하려고 합니다. 이 프로그램의 목적은 프로젝트에서 파일을 삭제하고 휴지통이라고도 알려진 삭제된 디렉터리에 저장하는 것입니다. 나는 이 일을 성공적으로 해낼 수 있었습니다.

또한 getopt 명령 -i(대화형)를 사용하여 Case 문을 전달하고 사용자에게 파일을 삭제할 것인지 묻는 질문을 촉발할 수 있었습니다.

이는 변수 "ision"을 생성하고 Case 문을 활성화할 때 이를 true로 설정함으로써 수행됩니다. 아래에 코드를 삽입했습니다. 몇 번 시도해 보았는데 모든 것이 괜찮아 보이지만 자세한 활동/모드를 추가하고 싶습니다. 누구든지 나를 도와줄 수 있나요?

#!/bin/bash

while getopts ":i:v" option ;
do
case "$option" in
i) echo "interactive mode set"
ision=true;
break;;
v) echo "verbose mode"
vison=true;
break;;
esac
done
echo "this is the proof we need"

echo $@

shift $(($OPTIND-2))

echo $@

echo "this is working too"

if [ ! -e ~/deleted ]
then
mkdir ~/deleted
fi

echo "the echo file was made or just created"

if [ $# -eq 0 ]
then
echo "safe_rm missing operand"
exit
fi

echo "all workking on the western front"

for i in $@
do

if [ "$ision" == "true" ]
then
echo "do you want to remobve the file"
echo "variable test $i"
echo "yes or no"
read -p "Enter " answer
if [ "$answer" == "no" ]
then
continue;
fi
fi

if [ ! -f $i ]
then
echo "no such file or directory"
exit
fi
        if [ $i == safe_rm ]
        then

        echo "cant remove safe_rm"
        continue
        fi

        if [ $i == safe_rm_restore ]
        then
        continue
        echo "cant remove safe_rm_restore"

        fi

inode=$(ls -i $i | cut -c -6 )
echo "the inode is $inode "
pathname=$(dirname $i)
if [ $pathname == "." ]
then
pathname=$(pwd)
echo $pathname
fi
basename=$(basename $i)
path=$basename"_"$inode":"$pathname"/"$basename

echo $path

if [ ! -f .restoreinfo ]
then
touch .restoreinfo
fi


echo $path >> .restoreinfo
mv $i ~/deleted/

done

답변1

여기서는 명령줄 구문 분석에 중점을 두겠습니다.

# defaults:
ision=0
vison=0

while getopts "iv" option; do
    case "$option" in
        i)
            echo "interactive mode set"
            ision=1 ;;
        v)
            echo "verbose mode"
            vison=1 ;;
        *)
            exit 1 ;;
    esac
done
shift $(( OPTIND - 1 ))

(( vison )) && echo 'This is a verbose message'

if (( ision )); then
   # interactive code
fi

정수라면 ision연산하기가 훨씬 쉬울 것입니다 . 그런 다음 위에서 보여준 것처럼 해당 값을 테스트 vison할 수 있습니다 .(( vison ))

또한 잘못된 명령 옵션 string 이 표시됩니다 getopts. 내가 아는 한 두 옵션 모두 매개변수가 없습니다. 즉, 문자열에 콜론이 있어서는 안 됩니다. 옵션이 인수를 취하는 경우 에 표시된 대로 콜론이 그 뒤에 와야 합니다 v:.

break명령줄을 구문 분석할 때 이 작업을 수행하지 마십시오. 구문 분석이 중지됩니다. 대신, 플래그를 설정하고 필요한 다른 작업을 수행하고 루프가 계속되도록 하세요. 나는 당신이 아마도 다음 중 하나인 C에 대한 지식을 가지고 있다고 가정합니다.하다필요는 진술(에서 ) break에서 나옵니다 . 여기는 다릅니다.caseswitch

디버깅 지원을 제외하고 명령줄을 구문 분석할 때 출력을 생성하지 마십시오. 많은 유틸리티에는 서로를 취소하는 플래그가 있습니다. 예를 들어 -v장황한 모드의 경우 -q"조용한" 모드이고 코드 출력이 "장황한 모드에 들어간 다음" "조용한 모드에 들어가는 것"은 소음일 뿐입니다.

그런데 비슷한 작업을 수행하려면(상호 배타적인 옵션 처리) 다음을 수행할 수 있습니다.

case "$option" in
    q)
        quiet=1
        verbose=0 ;;
    v)
        verbose=1
        quiet=0   ;;

    # etc.

사용자가 사용할 경우 -qv먼저 quiet1로 설정되고 그 다음에는 verbose0으로 설정되며 그 다음에는 값이 반전됩니다. 이 경우 명령줄을 수동으로 구성했는지 아니면 스크립트를 호출하여 구성했는지 알 수 없으므로 오류가 보고되지 않습니다.

exit 1알 수 없는 명령줄 옵션이 주어지면 실행될 명령문을 삽입했습니다 . 이는 사용자가 실수를 했다는 의미이고, 그 시점부터 명령줄에 있는 내용을 맹목적으로 신뢰하는 것은 위험할 수 있기 때문에 아마도 좋은 것입니다.

shift(해결된 옵션 제거)는 위와 같이 해야 합니다. Shift 키를 누르면 $OPTIND - 2인수 목록에서 너무 많은 항목이 제거됩니다.

또한 더 쉽게 읽을 수 있도록 들여쓰기를 개선하여 디버그 및 유지 관리도 더 쉽게 만들었습니다.


스크립트의 나머지 부분은 자세히 살펴보진 않았지만 인용되지 않은 변수 확장이 많이 발견되었습니다. 주어진 파일 이름에 공백(또는 다른 공백 문자)이 포함되어 있으면 문제가 발생할 수 있으므로 이 작업을 수행하지 마십시오.

특히 $@루프 등에서 사용되는 경우에는 따옴표가 필요합니다. 이렇게 하면 명령줄 인수가 공백(보다 정확하게는 내용 $IFS)으로 구분되는 것을 방지하고 이름에 글로빙 패턴 문자가 포함된 경우 실수로 파일 이름 글로빙을 방지할 수 있습니다.

꽤 많은 continue이론도 있습니다. IMHO 이러한 코드는 코드 흐름을 따르기가 어렵기 때문에 제거해야 합니다(특히 코드가 올바르게 들여쓰기되지 않은 경우). 그 자체로는 아무런 문제가 없지만 코드가 다양한 조건을 적절하게 처리하면 제거할 수 있습니다. 적어도 하나의 경우에는 명령문 echo바로 뒤에 명령문이 있습니다 continue. 이는 명령문이 실행되지 않음을 의미합니다 echo.

    continue
    echo "cant remove safe_rm_restore"

답변2

몇 가지 단축 비교를 사용할 수 있습니다. 이것은 C 및 기타 여러 언어의 ?: 표기법과 유사한 방식으로 나열된 if/then/else 문입니다. true인 경우 &&를 사용하여 비교를 실행하고 블록을 실행할 수 있으며, ||를 사용하여 블록을 실행할 수 있습니다. false이면 블록을 실행합니다.

$ vison=true 
$ [[ "$vison" == "true" ]] && vison=false || vison=true
$ echo $vison
false
$ [[ "$vison" == "true" ]] && vison=false || vison=true
$ echo $vison
true

자세한 로깅을 확인하기 위해 동일한 작업을 수행할 수도 있습니다.

[[ "$vison" == "true" ]] && echo "this is shown only in verbose mode"

답변3

쉘에는 불리언 값을 쉽게 표현할 수 있게 해주는 명령어 false와 명령어가 있습니다 . true자세한 정보를 표시하기 위해 일반적인 접근 방식은 로그 수준을 사용하는 것입니다. 여기서 각 발생은 -v로그 수준을 늘리거나 줄입니다.-q

interactive=false
log_level=1

log() {
  local level="$1"
  if [ "$level" -ge "$log_level" ]; then
    shift
    local IFS=" "
    printf '%s\n' "$*"
  fi
}


while getopts iqv option; do
    case $option in
        i)
            log 2 "interactive mode set"
            interactive=true;;
        v)
            log 2 "increasing log level"
            log_level=$((log_level + 1));;
        q)
            log 2 "decreasing log level"
            log_level=$((log_level - 1));;
        *)
            exit 1 ;;
    esac
done
shift "$((OPTIND - 1))"

log 2 'This is a verbose message'
log 3 'This is a debug message'

if "$interactive"; then
   # interactive code
fi

# or:

ask() { # args: var default question
  if "$interactive"; then
    printf %s "$3"
    IFS= read -r "$1"
  else
    eval "$1=\$2"
  fi
}

yesno() { # args: default question
  local answer="$1"
  ask answer "$1" "$2"
  case $answer in
    ([yY][eE][sS] | y | Y) return 0;;
    ([nN][oO] | n | N) return 1;;
    (*) case $1 in
          ([yY][eE][sS] | y | Y) return 0;;
          ([nN][oO] | n | N) return 1;;
          (*) log >&2 -1 "Wrong default value $default"; exit 1;;
        esac;;
  esac
}

if yesno no "Are you OK with that (yes/[no])? "; then
   log 1 OK do it
   ...
fi

위의 코드(테스트되지 않음)는 Debian 정책을 준수하므로 POSIX 또는 POSIX ( 그렇지 않은 경우 POSIX ) sh로 구성되었는지 여부에 관계없이 Debian에서 작동합니다 .dashlkshbashlocal

관련 정보