스크립트를 작성했지만 실행하면 다음과 같은 결과가 나타납니다.
./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
// 키워드는 실제로 이러한 키워드 뒤에 오는 모든 명령을 호출하고 반환 값에 대해 작동합니다.if
until
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_var
some_text
if[some_text
if[some_text
if
[
이것이것이 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
$1
cut
-b
43-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
의 합이 됩니다 . 동일한 원칙이 대체 항목이 있는 전체 행에 적용됩니다. 따라서 포함 및 명령 행이 있는 경우 쉘은 문자열을 다음으로 분할합니다 ( 하나의 인수로 명령 실행 ). 변수가 참조되는 경우에는 이런 일이 발생하지 않습니다 .abc
def
$key
abc def
foo$keybar
fooabc defbar
fooabc
defbar
"$key"