# !/bin/bash
# 주석 문구 추가
[Body of Bash Shell Script[
exit 0
#
: 주석 문구 생성을 위한 예약어. Java의 //와 동일한 역할#!/bin/bash
: 해당 파일이 쉘 스크립트임을 알리는 구문return 0
와 동일한 역할이렇게 만들어진 쉘 스크립트 파일은 주로 .sh
라는 확장자명을 가지고 있다.
# 1. 쉘 스크립트 파일에 실행 권한 부여
chmod +x [Shell Script 파일]
# 2. 실제 Script 실행
sh [Shell Script 파일]
위 과정을 통해 쉘 스크립트 파일을 작성하였지만 기본적으로 리눅스 측에서는 이 파일이 실행 파일인지 아닌지 알 수가 없다.
따라서 chmod 명령을 통해 일단 쉘 스크립트에 x 권한(실행 권한)을 부여해 실행 가능한 파일로 만드는 것이 선행되어야 한다.
이후 Script 실행은 sh
명령어를 통해 실행시킬 수 있다.
이때 sh 명령어 또한 Option을 부여할 수 있는데, 대표적으로 -v
옵션을 통해 Shell이 어디까지 제대로 수행되었는지 출력함으로써 오류 발생 여부를 확인할 수 있다.
이전에 말했듯 리눅스 콘솔 창은 Bash Shell이라는 쉘을 통해 명령어를 실행한다. 그렇다면 현재 실행 파일인 쉘 스크립트 이름만 입력하여 Bash Shell을 통해 쉘 스크립트를 실행할 수 있지 않을까?
정답은 “반만 맞다”이다.
윈도우에서 자바를 설치했다면 아마 자바를 설치한 뒤 환경 변수에 이를 추가해 줘야지만 정상적으로 자바 실행이 가능하다는 것을 알고 있을 것이다.
이처럼 환경 변수는 어떠한 프로그램이 실행될 수 있도록 실행 파일의 경로를 잡아주는 값을 의미한다.
말이 조금 어려울 수 있는데, 조금 더 풀어서 이야기해보자.
프로그램 한 개를 실행시킨다고 가정하자. 그런데 실행할 프로그램 경로가 상대 경로로 설정되어 있다면 문제가 발생할 것이다.
왜냐하면 상대 경로는 현재 디렉터리 기준으로 하는 경로인데 이러한 상대 경로로 프로그램을 실행시키려면 프로그램을 실행시킬 디렉터리가 매번 동일해야 하기 때문이다.
실제 컴퓨터 환경을 생각해 보면 바로가기 기능을 통해 실행 파일을 바탕화면에서 실행시킬 수도 있고 가끔은 다운로드 디렉터리 안에서 실행시킬 수도 있는데 이런 경우엔 프로그램 실행 환경이 매번 바뀔 것이므로 사용이 어려워질 것이다.
따라서 OS는 컴퓨터 프로그램을 실행시킬 때 절대 경로를 기준으로 실행시킨다.
그런데 여기에서 또 문제가 프로그램을 실행시킬 때마다 프로그램의 절대 경로를 외워 놓고 있다가 외운 경로를 그대로 입력해야 한다는 것인데 이는 귀찮기도 하고 에러도 많이 발생할 것이다.
이러한 문제 때문에 환경 변수라는 값이 생겨났으며 리눅스의 환경 변수 역할을 하는 것이 바로 PATH인 것이다.
리눅스의 PATH에는 실행하고자 하는 명령이나 프로그램의 상위 Directory들을 가지고 있다. 반대로 말하자면 PATH에 명시되지 않은 경로에 존재하는 실행 파일들은 (절대 경로를 입력하지 않는 이상) 실행시킬 수 없다는 것을 의미한다.
따라서 만약 PATH에 등록되어 있는 경로에 쉘 스크립트 파일이 존재한다면 이름만으로 실행시킬 수 있지만, 그렇지 않다면 이름만으로는 실행시킬 수 없는 것이다.
PATH 추가 방법에는 2가지 방법이 존재한다.
# 방법 1 : 환경 변수 PATH에 직접 주입
export PATH=$PATH:[추가하고자 할 디렉터리]
# 방법 2 : bashrc를 통한 설정
cd ~
→ vi .bashrc
→ export PATH=$PATH:[추가하고자 할 디렉터리] 문구 추가
→ source .bashrc
.bashrc는 별칭(alias)나 Bash가 수행될 때 실행되는 함수를 제어하는 지역적인 시스템 설정과 관련된 파일이다.
export PATH
같은 경우 모든 User에게, .bashrc는 PATH 구문을 파일에 추가한 User에게만 적용되므로 상황을 고려하여 방법을 선택하자.
PATH에 쉘 스크립트가 존재하는 경로를 추가하지 않더라도 ./[Shell Script 파일]
형식으로 쉘 스크립트를 활용할 수 있다.
./
은 "현재 디렉터리"를 의미하는데 리눅스 입장에서는 현재 디렉터리의 절대 경로를 이미 알고 있는 상태이다.
따라서 ./[Shell Script 파일]
을 입력할 경우 Linux에서는 Shell Script 파일이 존재하는 절대 경로를 아는 것과 마찬가지인 상황이므로 쉘 스크립트를 실행시킬 수 있는 것이다.
모든 변수는 "문자열(String)"으로 취급한다.
리눅스에서 모든 변수는 문자열로 취급하기 때문에 Java나 C언어 같은 프로그래밍 언어와는 다르게 변수 선언시 자료형을 입력하지 않아도 된다.
어차피 모든 변수는 문자열으로 취급되기 때문이다.
변수에 값을 대입할 때 "=" 좌우에 공백이 없어야 함
프로그래밍 언어에선 a = 3
처럼 공백이 존재하도록 변수 값을 지정해도 a에 3이 저장되지만 리눅스에서는 a=3
처럼 띄어쓰기가 존재하지 않아야지만 변수 지정이 가능해진다.
이는 띄어쓰기가 있을 경우 리눅스에선 모든 값을 Parameter로 인지하여 “a”, “=”, “3” 총 3개 값이 입력된 것으로 인지하기 때문이다.
변수 이름은 대소문자를 구분한다.
변수에 처음 값이 할당되면 자동으로 변수가 생성됨
Java에서 a라는 변수를 선언하지 않았는데 a=3
을 입력하면 그런 변수가 없다는 에러가 발생할 것이다.
하지만 위에서 말했듯 리눅스는 변수의 모든 자료형을 String으로 생각하기 때문에 변수를 미리 선언해야 할 필요성이 적다.
따라서 리눅스에선 선언되지 않았던 변수더라도 처음 값을 할당하면 먼저 변수를 선언하여 공간을 만든 뒤 값을 주입하는 행위까지 모두 수행해 준다.
변수에 지정된 값은 $
기호를 사용하여 $[변수명]
구문을 통해 저장된 값을 반환받을 수 있다.
실제 리눅스에서 어떻게 사용하는지 보며 이해하는 게 더 쉬우므로 아래 사진을 통해 이해하자.
추가로 read [변수명]
명령어를 입력하면 변수에 저장할 값을 입력할 수 있는 공간을 1라인 통째로 주기 때문에 더욱 편하게 값 입력이 가능해진다.
만약 붙여 넣기로 값을 입력하고 싶을 경우 이 방법이 더욱 편리할 수 있다.
‘ ‘(작은따옴표)
작은따옴표로 문자열을 감쌀 경우 일반적인 문자열로 만들어주는 특수 문자이다.
중요한 점은 작은따옴표는 모든 특수 기호 또한 일반 문자로 간주하여 처리한다는 것이다.
“ “(큰 따옴표)
큰 따옴표로 문자열을 감쌀 경우 일반적인 문자열로 만들어주는 특수 문자이다.
위에서 설명한 ‘ ‘
와 다른 점은 큰 따옴표의 경우 $
, ₩(백 쿼터)
, \
를 제외한 모든 특수 기호를 일반 문자로 간주하여 처리한다.
반대로 말하자면 위 3개의 특수 기호는 그 기능을 잃지 않는다는 것이다.
큰 따옴표는 여러 변수를 사용할 경우 변수를 구분할 때 사용하거나 변수를 1개만 불러올 때 사용한다.
위 사진을 보면 $variance
에서 $
는 그 역할을 다하지만 ?
의 경우 문자 1개를 대체하는 와일드카드의 역할을 잃어버렸음을 알 수 있다.
\(역 슬래쉬)
특수문자 바로 앞에 사용될 경우 뒤에 나오는 특수 문자의 효과를 없애 일반 문자처럼 처리하는 특수 문자이다.
이는 다른 프로그래밍 언어나 심지어 벨로그에서도 이러한 역할을 수행하므로 따로 예시를 보이진 않겠다.
참고로 명령어 맨 뒤에 \
가 나온다면 이는 무효화할 명령어가 "엔터"가 된다. 즉, 엔터를 무효화므로 아래 줄에 있는 명령어와 현재 줄의 명령어가 연결되는 결과로 이어진다.
;
명령어 2개를 한 줄에 표현하기 위해 사용하는 특수 문자이다.
|
와는 다르게 ;
기준으로 앞 뒤에 있는 명령어는 서로 영향을 주지 않으며 단순히 왼쪽 명령어부터 차례대로 실행될 뿐이다.
basename
basename [경로] [확장자]
입력한 경로 중 가장 하위에 존재하는 파일(혹은 디렉터리) 이름만 추출하는 명령어이다.
확장자는 선택 옵션으로 만약 확장자명을 입력할 경우 확장자까지 제거하여 파일 이름을 추출해 준다.
(사실 확장자라고는 써놨지만 문자열의 마지막 부분을 일치하는 범위까지 삭제하는 것이다)
cmp
cmp는 compare의 약자로써 2개 파일의 차이를 비교할 때 사용한다.
Linux 콘솔창에서 cmp를 사용하면 2개 파일의 동일 여부와 어떤 부분이 다른지까지 알려주는데 쉘 스크립트에서는 조건식으로도 사용할 수 있다.
(동일한 파일일 경우 True, 다른 파일일 경우 False)
실제 예시를 통해 확인해 보자.
a.txt와 b.txt는 동일한 파일이며 c.txt는 다른 파일이다.
일단 아래와 같은 쉘 스크립트 파일을 만든 뒤 실행시켜 보자.
#/bin/bash
if cmp a.txt b.txt
then
echo "True"
else
echo "False"
fi
동일한 파일이므로 True를 반환한다.
이젠 b.txt를 c.txt로 바뀐 뒤 다시 실행시켜 보자.
위 사진에서 보면 False 결과값이 정상적으로 출력되지만 동시에 cmp
명령어의 결과 또한 같이 출력됨을 볼 수 있다.
cmp
명령어의 출력문까지는 궁금하지 않으므로 if cmp a.txt b.txt
를 if cmp a.txt b.txt 1>/dev/null
로 바꿔주면 cmp
결과값이 출력되지 않을 것이다.
현재 접속한 사용자의 Username을 출력하는 명령문이다.
권한 등을 사용자 명을 통해 제한하고 싶으면 사용할 수 있다.
sleep [시간]
지정한 시간만큼 잠시 쉘 스크립트 실행을 중지하는 명령문이다.
기본적으로 시간에는 자연수뿐 아닌 소수 또한 사용할 수 있다.
기본적인 시간의 단위는 초(s)이고, s(초), m(분), h(시간), d(단위) 같은 단위를 붙여 단위 시간으로도 실행 중지 시간을 지정할 수 있다.
tr [Option] [문자열1] [문자열2]
문자열1을 문자열2로 바꿔주는 명령문이다.
tr
은 문자열1과 동일한 문자열만 바꾸는 것이 아니라 문자열1의 N번째 문자를 문자열2의 N번째 문자로 바꾸는 명령어이다.
예를 들어 tr abc def
라는 명령어를 입력했다 가정하자.
이때 문자열에 대한 변환 전후는 아래와 같다.
abc
def
ab
de
b
e
문자열1과 완전히 동일하지 않더라도 문자 사이에 치환이 되는 것을 확인할 수 있다.
만약 문자열 길이가 다를 경우 짧은 문자열의 마지막 문자로 짧은 문자열을 연장하여 문자열의 길이를 맞춰준 뒤 문자열 치환이 시작된다고 생각하면 된다.
-c
: 문자열1에 포함된 문자를 제외한 모든 문자를 문자열2의 마지막 문자로 치환\n
도 대체함-n
: \n
은 치환되지 않도록 함 -d
: 문자열1에 존재하는 문자들 삭제cut
cut [Option] [구문]
라인 구문을 정해진 기준에 따라 처리한 뒤 선택한 부분을 추출하는 명령어이다.
이렇게 설명하니 조금 어려운데, 예를 들어 i am peter
라는 구문에서 띄어쓰기를 기준으로 자른 뒤 2번째 문자열(am)을 추출하고 싶을 때 활용하는 명령어가 cut이다.
-d
, --delimiter
옵션 뒤에 지정한 문자를 구분자로 하여 구문을 자르게 하는 옵션이다.
기본적인 구분자는 TAB
으로 설정되어 있다.
만약 띄어쓰기를 구분자로 구문을 자르고 싶다면 cut -d ' '
처럼 사용하면 된다.
-f
, --fields
-d
옵션을 통해 잘라진 문자열들 중 사용할 필드를 지정하는 Option이다.
-f4
처럼 -f
옵션 뒤에 숫자를 바로 붙여 사용하며 -f2,4
처럼 여러 개의 문자열을 가져올 수도 있다.
expr
expr
은 식을 계산하는 명령어로써 사용방법은 expr [연산]
으로 매우 간단하다.
expr은 사용법보다는 입력할 연산에 대해 잘 알아둘 필요가 있다.
expr
은 명령어이기 때문에 변수 지정과는 다르게 띄어쓰기를 통해 연산자와 피연산자를 구분해줘야 한다.
즉, expr 5 + 1
처럼 연산에 띄어쓰기가 되어있어야 정상적으로 연산이 가능하다.
expr
이 사용할 수 있는 연산자는 아래와 같다.
+
, -
, *
, /
, %
|
(or), &
(and)=
, >
, >=
, <
, <=
, !=
:
(일치 혹은 substitute)추가로 알아둬야 할 것은 expr
이 사용하는 문구 중 >
, <
, *
같은 것들은 역할을 가지고 있는 특수 문자로 사용되고 있다.
따라서 쉘 스크립트 측에서 명령을 실행할 때 헷갈리지 않게 \
를 연산자 앞에 붙여주나 연산자 앞뒤를 따옴표(큰 따옴표, 작은따옴표 상관없음)로 감싸줘야 한다.
echo
echo [문자열]
문자열을 출력하는 간단한 명령어이다.
echo
단독으로 활용한다기보다는 echo [문자열] > a.txt
와 같이 Redirection과 같이 활용하여 다른 파일에게 값을 전달해 주는 용도로 많이 활용한다.
sed [Option] “s/바꿀패턴/바뀐 후 패턴/g” 파일이름`
스트림 에디터를 활용하여 문자열을 치환하는 용도로 많이 활용된다.
위에서 이미 문자열을 치환하는 tr
이 있었는데 왜 sed
라는 새로운 명령어가 필요할까?
위에서도 말했지만 tr
은 사실 문자열을 치환한다기보다는 N번째 문자끼리 치환된다고 보는 것이 맞다.
하지만 리눅스를 사용하다 보면 완전히 일치하는 문자열들만 치환하고 싶을 경우가 있을 것이다.
이럴 때 활용하는 명령어가 sed
인 것이다.
sed 중 /g
같은 경우 찾은 모든 문자열에 대하여 치환을 하라는 구문이다.
예를 들어 abc abc
가 있을 때 abc
를 def
로 치환한다면 /g
가 없을 경우 def abc
로, /g
가 있을 경우 def def
로 치환될 것이다.
-i : 변경된 내용을 파일에 적용
sed
를 활용하므로 거의 필수 값이라 봐도 무방-r : 확장 정규식 패턴 사용
exit 0
정상적으로 쉘 스크립트 실행이 끝났음을 의미한다.
exit 1
어떠한 이유로 비정상적으로 쉘 스크립트 실행이 끝났음을 의미한다.
" "
큰 따옴표 사이에 띄어쓰기가 있을 경우 빈 공간(Space)의 의미를 가진다.
""
큰 따옴표 사이에 띄어쓰기가 없을 경우 Null
값을 의미한다.
$
$
는 변수 값을 반환시키는 것 이외에도 다양한 역할을 수행할 수 있다.
$?
최근 실행한 명령이나 쉘 스크립트의 종료 스테이터스를 출력하는 구문이다.
정상적으로 끝났으면 0을, 비정상적으로 끝났으면 exit 1
이 실행되었을 것이므로 `이 반환될 것이다.
$n
파라미터 변수를 의미하며 입력한 명령어 중 n번째로 기입된 파라미터를 의미한다.
여기에서 잘 알아둬야 하는 것이 명령어의 파라미터는 0번부터 시작한다는 점이다.
yum -y install net-tools
$0
: yum$1
: -y
$2
: install$3
: net-tools$@
모든 Parameter를 별도의 문자로 취급한다.
$*
모든 Parameter를 하나의 단어로 취급한다.
사실 $@
와 $*
는 설명만 봐서는 이해가 쉽지 않다.
하지만 예시를 보면 바로 이해 가능하므로 예시를 통해 알아보자.
hello hi
$*
: "hello hi"를 1개의 단어로 취급$@
: "hello", "hi" 총 2개의 단어가 입력된 것으로 취급$#
입력한 모든 Parameter의 개수를 의미한다.
이때 중요한 것이 $0
, 즉 0번째 Parameter는 그 개수에서 제외한다는 점이다.
예를 들어 man
을 입력했을 경우 $#
은 0을 반환한다.