https://mug896.github.io/bash-shell/basics.html의 내용을 간단히 정리한다.
Shell의 기본 역할
사용자에게 명령을 입력받아 실행한다.
사용자는 명령어 작성 시 사용할 수 있는 기능을 사용하여 명령을 작성하기 때문에, 실제 실행 전에 shell에 의해 해석 단계를 거친다.
명령어 작성 시 사용할 수 있는 기능
파일명
명령 실행 시 사용되는 이름과 같다.
리눅스에서 사용하고 있는 파일 시스템에서는 NUL, / 두 개의 문자를 제외하고 전부 파일명이 될 수 있다.
공백
명령은 기본적으로 공백으로 분리하여 작성한다.
command arg1 arg2 arg3 ...
제일 처음으로 명령어가 위치하고, 공백 이후로는 매개변수가 이어질 수 있다. 매개변수는 공백으로 구분한다.
[의 경우 if문에서 사용되는 명령으로, 마지막에 인수로 ]를 필요로 한다. 아래에 오류가 발생하는 경우와 정상적으로 실행하는 경우를 정리해둔다.
# [ 명령과 첫번째 인수 10 을 붙여 사용하여 오류 발생 ('[10' 가 명령 이름이 됩니다.)
$ [10 -eq 10 ]; echo $?
[10: command not found
# 마지막 인수 ] 를 10 과 붙여사용하여 오류 발생 ('10]' 가 하나의 인수가 됩니다.)
$ [ 10 -eq 10]; echo $?
bash: [: missing ']'
# [ 명령에서 사용되는 연산자들도 모두 인수에 해당합니다.
# 다음의 경우 인수들 사이에 공백을 두지않아 a=b 가 하나의 인수로 인식이 됩니다.
# 그러므로 스트링 "a=b" 과 같은 의미가 돼서 항상 참이 됩니다.
$ [ a=b ]; echo $?
0
# 인수들 사이에 모두 공백을 띄워서 정상적으로 실행되었습니다.
$ [ a = b ]; echo $?
1
단, 대입 연산은 공백을 두어 작성하면 오류가 발생한다. Shell Script 작성 시 대입 연산을 제외하고 모두 공백을 두어 작성하면 오류를 줄일 수 있다.
# 변수 AA 가 명령이 되고 = , 10 는 각각 인수로 인식됩니다.
$ AA = 10
AA: command not found
# 그러므로 shell 에서 대입연산은 반드시 공백 없이 붙여 사용해야 합니다.
$ AA=10
$ echo $AA
10
참/거짓
Shell에서는 0이 참(True), 그리고 프로그램의 정상 종료를 나타낸다. 그리고 0이 아닌 모든 수가 거짓(False)과 프로그램의 오류를 나타낸다.
참/거짓의 판단 또한 명령의 종료 상태 값($?)으로만 수행한다.
💡 $?
Shell에서 명령의 종료 상태 값을 나타내는 특수 변수
# 전달받은 인수값를 그대로 리턴하는 함수. '$1' 는 첫번째 인수를 나타냄
$ func() { return $1 ;}
# 'func 0' 은 종료 상태 값으로 0 을 리턴하므로 참
$ if func 0; then echo true; else echo false; fi
true
# 'func 1' 은 종료 상태 값으로 1 을 리턴하므로 거짓
$ if func 1; then echo true; else echo false; fi
false
return
연산 결과를 반환하는 프로그래밍 언어와 다르게 종료 상태 값을 지정하는 데 사용한다.
연산 결과는 stdout 출력에 해당한다.
$ func() { expr $1 + $2 ; return 5 ;}
$ func 1 2
3
$ echo $? # $? 는 명령의 종료 상태 값을 나타내는 특수 변수
5
명령 종료 문자
Shell Script는 개행을 인식하기 때문에 문장 끝에 ;(명령 종료 문자)를 반드시 붙일 필요는 없다. 하지만 개행을 하지 않고 한 줄에 연이어 작성하는 경우에는 ;를 붙여야 한다.
특히 명령 grouping을 위한 중괄호 사용 시에는 명령의 인수를 구분할 수 있도록 ;를 붙여야 한다.
단, subshell을 만들 때 사용되는 소괄호 같은 메타 문자는 공백이나 ;를 신경 쓰지 않아도 된다.
# 명령들을 한줄에 연이어 쓸 경우는 ';' 를 붙여야 한다.
$ for i in {1..3} do echo $i done
> 오류
$ for i in {1..3}; do echo $i; done
1
2
3
# 'echo 1 }' 하면 '}' 까지 프린트된다. 인수와 구분을 위해 ; 를 붙여야 한다
$ { echo 1 } ;}
1 }
$ { echo 1; echo 2 }
> 오류
$ { echo 1; echo 2 ;}
1
2
Escape
명령문에 Shell에서 제공하는 키워드, 메타문자, glob 문자와 동일한 문자가 사용되면 오류가 발생할 수 있다.
💡 glob
컴퓨터 프로그래밍에서, 특히 유닉스 계열 환경에서 glob 패턴은 와일드카드 문자에 해당하며 여러 파일 이름의 집합을 지정한다.
간단히 말해 Shell에 예약어가 포함되어 오류가 발생하는 경우, escape 또는 quote를 이용해 명령문을 위한 문자열로 변환해주어야 한다.
# 명령문에 shell 에서 사용하는 glob 문자 '*' 가 포함되어 에러 발생
$ expr 3 * 4
expr: syntax error
# 다음과 같이 escape 하거나 quote 하여 명령문을 위한 스트링으로 만들어줌
$ expr 3 \* 4
$ expr 3 '*' 4
12
# '<' , '>' 문자는 shell 에서 사용되는 redirection 메타문자
# 마찬가지로 escape 하지 않으면 정상적으로 실행되지 않고 오류가 발생합니다
$ [ a \< b ]
$ test a \> b # 모두 escape 해줘야 한다.
$ expr 3 \> 4
# '( )' ';' 문자도 shell 에서 사용하는 메타문자
$ find * ( -name "*.log" -or -name "*.bak" ) -exec rm -f {} ;
bash: syntax error near unexpected token '('
# 다음과 같이 모두 escape 해줘야 오류없이 정상적으로 실행이 됩니다.
$ find * \( -name "*.log" -or -name "*.bak" \) -exec rm -f {} \;
참고 문서