POSIX 및 이식성 | grep -s, grep -q |

POSIX 및 이식성 | grep -s, grep -q |

나는 쉘 스크립트 이식성을 선호합니다.

하지만 지금은 너무 멀리 갔는지 모르겠습니다.

이 예에는 confirmation첫 번째 인수를 질문이 포함된 문자열로 받아들이고 다른 모든 인수는 유효한 답변이 가능한 함수가 있습니다.


confirmation ()
{
    question=$1; shift; correct_answers=$*

    printf '%b' "$question\\nPlease answer [ $( printf '%s' "$correct_answers" | tr ' ' / ) ] to confirm (Not <Enter>): "; read -r user_answer

    # this part iterates through the list of correct answers
    # and compares each as the whole word (actually as the whole line) with the user answer
    for single_correct_answer in $correct_answers; do
        printf '%s' "$single_correct_answer" | grep -i -x "$user_answer" > /dev/null 2>&1 && return 0
    done

    return 1
}

confirmation 'Do you hate me?' yes yeah kinda

보시다시피 핵심 부분이 Exploiting 되어서 grep살펴봤습니다.매뉴얼 페이지, 그리고 이것을 발견했습니다:

-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was detected. Also see the -s or --no-messages option. (-q is specified by POSIX .)
-s, --no-messages
Suppress error messages about nonexistent or unreadable files. Portability note: unlike GNU grep, 7th Edition Unix grep did not conform to POSIX , because it lacked -q and its -s option behaved like GNU grep's -q option. USG -style grep also lacked -q but its -s option behaved like GNU grep. Portable shell scripts should avoid both -q and -s and should redirect standard and error output to /dev/null instead. (-s is specified by POSIX .)

이 부분을 강조해 보겠습니다.

이식성 참고 사항: GNU와 달리 grepUnix의 일곱 번째 버전 grepPOSIX, 부족 -q하고 옵션이 GNU 의 옵션 -s과 유사하게 작동하기 때문입니다 . USG 에도 특징이 부족 하지만 옵션은 GNU와 유사하게 작동합니다 . 이식 가능한 쉘 스크립트는 및 사용을 피해야 하며 표준 출력 및 오류 출력을 .grep-qgrep-q-sgrep-q-s/dev/null


너무 멀리 갔습니까? 아니면 /dev/null유일한 휴대용 방법으로 리디렉션하고 있습니까?


아니요40년 전 운영체제 버전의 이식성에 집중하세요!

답변1

유닉스 V7은 1970년대 후반에 출시됐다. 이것은 Bourne 쉘을 도입한 버전입니다.

그러나 당시 추가된 기능 지원은 없었으며 readno -rprintf명령도 없었습니다. 대소 문자를 구분하지 않는 것은 Bourne이 grep아닙니다 .grep -y$(...)

그 이후로 유닉스 계열 시스템은 많이 발전하고 다양해졌습니다. 1990년대 초 POSIX는 어느 정도 통일성을 회복하려고 노력했습니다.

그러나 기본 구현에서 POSIX를 준수하지 않고 POSIX 호환 구현만 별도 유틸리티로 추가하는 일부 시스템이 여전히 있습니다.

예를 들어 Solaris는 POSIX보다 /bin/grepV7에 더 가깝습니다 . Solaris의 POSIX를 사용할 수 있습니다 (Solaris의 최소 배포에서는 사용할 수 없음).grepgrepgrep/usr/xpg4/bin/grep

/bin/grep-q솔라리스에는 , -E, 가 없습니다 -F.

/usr/xpg4/binSolaris에서 작업할 때 일반적으로 앞에 놓고 대신 $PATH사용 하려고 합니다 (Solaris 11에서는 변경되었지만 /bin/sh는 이제 ksh93이므로 버그 기반 ksh88보다 평균적으로 POSIX 호환이 더 높습니다 )./usr/xpg4/bin/sh/bin/sh/usr/xpg4/bin/sh

코드에 대한 기타 이식성 참고 사항:

  • correct_answers=$*또는 의 동작은 read -r의 현재 값에 따라 달라집니다 $IFS. ( 위치 매개변수는 입력을 단어로 분할 하는 데 사용되는 첫 $*번째 문자와 연결됩니다 .) 따라서 원하는 값으로 설정해야 합니다.$IFSread$IFS

    위치 인수를 스칼라 문자열로 연결하면 구분 기호가 포함된 경우 NL을 구분 기호로 사용하지 않으면 제대로 작동하지 않습니다. read어쨌든 한 줄만 읽혀 답변이 포함되지 않기 때문입니다. 개행 문자.

  • 시퀀스를 확장 %b하려는 의도가 아닐 수 있는 내용을 -formatted 매개변수에 포함시켰습니다 .\x

  • for single_correct_answer in $correct_answers분할+글로브를 사용하세요. 나는 여기서 전역 부분을 원하지 않는다고 생각하며 나중에 다시 분할하기 위해 다시 연결하는 것은 약간 어리석은 일입니다(신뢰할 수 없음).

  • grep -i -x "$user_answer"대소문자를 구분하지 않고 비교하는 대신 정규식 패턴 일치를 수행합니다. 또한, 답변이 로 시작하는 경우에는 옵션이므로 -작동하지 않습니다 .grep

  • printf '%s' text텍스트가 아닌 출력(줄 바꿈 누락)을 생성하므로 동작이 grep지정되지 않습니다(그리고 실제로 이식할 수 없습니다).

따라서 이러한 점을 염두에 두고 코드를 다음과 같이 변경합니다.

confirmation()  {
    question=$1; shift

    printf '%s\nPlease answer [' "$question"
    sep=
    for answer do
      printf %s "$sep$answer"
      sep=/
    done
    printf '] to confirm (Not <Enter>): '
    IFS= read -r user_answer

    # this part iterates through the list of correct answers
    # and compares each as the whole word (actually as the whole line)
    # with the user answer
    for single_correct_answer do
      printf '%s\n' "$single_correct_answer" |
        grep -ixFqe "$user_answer" && return
    done

    return 1
}

관련 정보