핵심 문제

핵심 문제

스크립트를 작성했지만 실행하면 다음과 같은 결과가 나타납니다.

./autotex: line 7: syntax error near unexpected token `then'
./autotex: line 7: `            then'

스크립트는 다음과 같습니다

#!/bin/bash

while [ $key = "q"]; do

        dateTex = grep $1.tex| cut -b 43 - 54
        datePdf = grep $1.pdf| cut -b 43 - 54
        if[$dateTex !eq $datePdf]
        then
                pdflatex $1.tex
        fi

        read -t 1 -n 1 key

done

답변1

while [ $key = "q"]; do

~해야 한다

while [ $key = "q" ]; do

그리고

if[$dateTex !eq $datePdf]

~해야 한다

if [ "$dateTex" != "$datePdf" ]

언급 할 필요없는

dateTex = grep $1.tex| cut -b 43 - 54

또 다른 유사한 줄이 끊어져 다음과 같이 표시됩니다.

dateTex=$(grep something $1.tex | cut -b 43-54)

답변2

핵심 문제

다른 많은 프로그래밍 언어와 달리 Bourne 쉘 구문에는 특히 특정 위치의 공백과 관련된 특정 특성이 있습니다. 혼란스러워지는 부분은 다음과 같습니다.

[이것이 다음과 같다는 것을 기억하는 것이 중요합니다.주문하다, ]최종적인 문법적 특징(각주 1)이 아닙니다.토론이 명령에.

Bourne(및 유사한/파생) 쉘에서 공백(각주 2)은 명령과 해당 인수를 구분하며 while// 키워드는 실제로 이러한 키워드 뒤에 오는 모든 명령을 호출하고 반환 값에 대해 작동합니다.ifuntil

Bourne 쉘의 또 다른 특이한 속성(코드에서 문제처럼 보이는)은 공백에 특정한 변수 할당입니다.아니요변수 이름, 기호 =및 할당된 내용 사이의 공백입니다.

게다가 명령의 출력은 대부분의 언어에서와 같이 자동으로 변수로 들어가지 않습니다. 이를 위해서는 "명령 대체"를 사용해야 합니다. 새롭고 중첩 가능하며 더 널리 권장되는 구문은 $(command to run)(각주 3)입니다.

코드의 예

따라서 위의 내용을 코드에 적용하십시오.

while [ $key = "q"]; do

..문제는 입니다 "q"]. 쉘은 이를 test/ 명령에 대한 [인수 로 처리합니다. ( q]따옴표는 여기서도 아무 작업도 수행하지 않습니다. 쉘에는 변수 유형이 없습니다. 일부 컨텍스트를 제외하고는 모든 것이 문자열이므로 q이미 문자열 - 특수 문자를 이스케이프하기 위한 따옴표) 나는 이것을 다음과 같이 고칠 것이다:

while [ "$key" = q ]; do

..또한 $key항상 올바르게 해석되도록 인용합니다(각주 4). 여기서도 동일한 문제(및 또 다른 문제)가 발생합니다.

if[$dateTex !eq $datePdf]

..셸은 공백을 사용하여 한 항목이 끝나고 다른 항목이 시작되는 위치를 알려준다는 점을 기억하세요(다시 말하지만, 각주 2). 라고 말하면 먼저 , getting 로 if[$some_var대체되고 , 그런 다음 명령에 대한 name 실행을 시도합니다 . 따라서 먼저 공백을 사용해야 합니다 .$some_varsome_textif[some_textif[some_textif[

이것이것이 then바로 코드가 오류를 인쇄하는 이유입니다. bash는 을 본 후에만 a를 기대 if하지만 결코 보지 않고 완전히 다른 명령/토큰으로 구문 분석되는 을 if봅니다 .if[$dateTex

, 및 를 [구분하기 위해 공백을 사용하는 이유도 같은 원리입니다 .$dateTex$datePdf]

마지막으로 !eq명령 인식을 [위한 유효한 인수/테스트가 아닙니다. 주변의 인수를 정수로 해석하고( 인용 여부에 관계없이 -eq명령을 입력하는 쉘에 관한 한 여전히 문자열입니다 ) 동일한지 비교합니다. [부정 연산자에 대한 귀하의 생각은 정확 !하지만 셸의 다른 많은 항목과 마찬가지로 [다른 매개변수 앞에 별도의 매개변수여야 합니다. 그래서 당신은 원합니다:

if [ ! "$dateTex" -eq "$datePdf" ]

..또는 명령 대신 쉘의 부정 연산자를 사용할 수 있습니다 [(공백에 다시 주의하십시오. 쉘 구문이 공백으로 분할되면 별도의 토큰/필드여야 합니다).

if ! [ "$dateTex" -eq "$datePdf" ]

또한 다른 답변에 따르면 =두 매개 변수 문자열이 동일한지 확인하고(비교하기 전에 매개 변수 문자열을 정수로 해석하는 대신 ) 두 문자열이 다름인지 확인하는 -eq특수 사례 부정 연산자도 지원합니다 . !=사용 사례에서 문자열 비교만으로 충분하다면 다음 중 하나를 사용할 수 있습니다.

if [ "$dateTex" != "$datePdf" ]  # != operator
if [ ! "$dateTex" = "$datePdf" ] # test ! operator with test = operator
if ! [ "$dateTex" = "$datePdf" ] # shell ! operator with test = operator

이제 변수 할당이 포함된 다음 줄로 이동합니다.

dateTex = grep $1.tex| cut -b 43 - 54
datePdf = grep $1.pdf| cut -b 43 - 54

첫째, 쉘이 구문 분석하는 방법은 확장된 내용에 따라 인수 및 하나 이상의 인수를 사용하여 명령을 실행하는 것입니다(다시 각주 4 ) dateTex = grep $1.tex. 따라서 두 번째 로 이 명령 의 경우 옵션은 목록을 하나의 인수로 사용하므로 공백 없이 하나로 병합하기를 원합니다 . 어쨌든 명령 대체를 사용하려는 것 같으므로 다음과 같은 것을 원합니다.dateTex=grep$1$1cut-b43-54

dateTex=$(grep "$1".tex | cut -b 43-54)

..그리고 다른 라인에도 동일한 작업을 수행합니다. 마지막으로 grep filename뭔가 잘못된 것 같습니다. grep첫 번째 인수(옵션 외)는 검색/일치할 패턴이어야 합니다. 따라서 예제 코드에 이를 작성하면 stdin에서 읽고 "$1".tex확장되는 패턴을 검색합니다. 아마도 파일에서 "$1".tex어떤 패턴을 검색하고 싶을 것이므로 이 작업을 수행해야 합니다 grep pattern "$1".tex.

이 모든 작업을 수행한 후에 실제 코드가 게시한 코드와 다르거나 그보다 더 많은 오류 메시지가 인쇄되는 것으로 의심됩니다.

각주

[1] 이 명령은 test이며 [명령을 호출할 수 있는 또 다른 이름입니다. 유일한 차이점은 호출할 때 마지막 인수를 예상한다는 것입니다. 기술적으로 대부분의 구현에서는 내장 셸이지만 구문 규칙은 동일합니다.test]]

[2] 기술적으로는 IFS(내부 필드 구분 기호) 변수에 있는 모든 것이지만 일반적으로 공백, 탭 및 줄 바꿈입니다(줄 바꿈은 다른 이유로 인해 약간 특별합니다).

[3] 오래되었지만 중첩되지 않은 구문은 `command to run`- 매우 오래되었거나 다소 비표준적인 쉘(예: Solaris 10 /bin/sh)에서 스크립트를 실행하려는 경우 개인적으로 이 구문이 매우 좋다고 생각하지만 그렇지 않습니다. 스크립트에 중첩이 필요하다고 생각합니다(새 구문의 유일한 실제 이점). 하지만 대화형 명령줄 사용을 어떻게 더 쉽게 만들 수 있는지 알 수 있습니다.

[4] 변수를 따옴표로 묶지 않으면 $IFS변수가 대체된 후 변수의 공백(또는 각주 1에 있는 모든 항목)이 평가되고 전체 줄에서 "필드 분할"이 다시 수행됩니다. 따라서 $key설정되지 않은 경우 공백이거나 그냥오직따옴표가 없는 공백 문자는 기본적으로 명령에서 "사라집니다". 포함 과 같은 혼합이 있는 경우 $key이를 추가 하면 두 매개변수 abc def의 합이 됩니다 . 동일한 원칙이 대체 항목이 있는 전체 행에 적용됩니다. 따라서 포함 및 명령 행이 있는 경우 쉘은 문자열을 다음으로 분할합니다 ( 하나의 인수로 명령 실행 ). 변수가 참조되는 경우에는 이런 일이 발생하지 않습니다 .abcdef$keyabc deffoo$keybarfooabc defbarfooabcdefbar"$key"

관련 정보