Information Security Study

240118 셸 스크립트(source와 .의 차이, .profile, 전역 경로, 변수, quote, 치환, 파라미터, 제어문, $?) 본문

네트워크 캠퍼스/Linux

240118 셸 스크립트(source와 .의 차이, .profile, 전역 경로, 변수, quote, 치환, 파라미터, 제어문, $?)

gayeon_ 2024. 1. 18. 15:54

source와 . 실행의 차이점 살펴보기

test1.sh 를 생성해주세요

#!/bin/bash
poiuqwer /

 

이제 위의 셸 스크립트는 poiuqwer라는 사전에 지정된 적이 없는 리눅스 명령어를 실행한다.

이를 위해서 alias에서 별명을 등록해야 한다.

 

$ alias poiuqwer=’ls -alF’

먼저 해당 명령을 실행하면 이제 poiuqwer은 ls -alF을 대체해서 사용할 수 있다.

 

 

단 source명령어는 해당 sh파일을 수행하지만

. 명령어는 해당 sh파일을 수행하지 못한다.

권한을 부여했는데도 실행하지 못한다.

 

. 명령어로 sh파일을 수행하지 못하는 이유

  • source 명령어는 현재 셸에서 실행하도록 되어있지만
  • .명령어는 새로운 셸을 하나 더 순간적으로 열어서 실행하는데
  • 이 때, 새로 연 셸에는 alias 설정이 되어있지 않기 때문이다.

 

 

셸 스크립트의 배치

셸 스크립트를 여기저기 중구난방으로 작성하면 해당 경로를 찾아들어간 다음

그곳에서

$ ./파일명.sh

와 같은 형식으로 실행해야 하는데 파일이 많아지면 많아질 수록 관리하기 힘들어진다.

 

따라서 이를 방지하기 위해서 셸 스크립트들을 모아두는 디렉터리를 하나 작성한 다음

그곳에 작성된 셸 스크립트들은 어디서건 그냥 파일명만 적어도 실행되게 만든다면 편할 것이다.

 

먼저 모든 셸 파일들을 저장할 수 있는 폴더를 만든다.

편의상 ~ 경로 하위에 bin 폴더로 만들 것이다.

$ mkdir ~/bin

 

그리고 셸 스크립트 파일들을 전부 옮긴다.

$ mv 파일명.sh ~/bin

ls로 ~/bin 하위 스크립트를 확인해보면 세 파일 모두 잘 이동했다.

(mv *.sh로도 셸 스크립트를 모두 옮길 수 있다.)

 

그리고 검색경로에 ~/bin을 추가하기 위해

vim으로 ~/.profile 파일을 열어 다음과 같이 추가한다.

PATH="$PATH:~/bin"

위의 명령어는 환경변수 PATH에 ~/bin을 추가하는 것이다.

파일 마지막에 추가한다.

 

$ source ~/.profile

을 실행하면 즉시 적용된다.

(파일명 앞에 .이 붙은 건 보이지 않는 파일)

 

이제 해당 작업을 수행한 계정 기준으로는 어디서건 .sh 파일을 호출할 수 있다.

 

$ 파일명.sh

를 입력하면 어떤 경로에서건 해당 파일을 ~/bin 폴더에서 읽어와 실행한다.

(PATH를 추가해서 가능한 것이다.)

 

 

전역 경로 비활성화

$ ls homesize.sh

는 현재 경로에 homesize.sh가 없다면 실행되지 않는다.

 

그러나

$ source homesize.sh

는 실행된다.

 

따라서 source 명령어를 쓸 때는 해당 단축경로를 비활성화 하고 싶다면

$ shopt -u sourcepath

를 수행하면 된다.

source 명령어로 셸스크립트를 수행하는 건 불가능하지만

 

profile 내부에 어디에서든지 호출할 수 있도록 환경변수를 설정했기 때문에

여전히 그냥 파일명으로만 호출하는 건 가능하다.

 

 

여러 줄 셸 스크립트 작성하기

실제로는 셸 스크립트는 여러줄로 된 스크립트를 작성하는것이 일반적이다.

여러 줄 명령어를 순차적으로 실행시킬 때는 기본적으로 엔터키를 눌러 개행시키면

순차적으로 하나씩 명령을 실행한다.

 

rootls.sh

#!/bin/bash

echo "root"
cd /
ls -l

위 명령어는 루트디렉토리의 상세정보를 보여준다.

 

 

 

엔터키로 개행시키는 대신 ;을 statement(문) 하나하나마다 붙여줘도 잘 동작한다.

#!/bin/bash

echo "root";cd /;ls -l

가운데 빈 칸은 실행 구문으로 취급되지 않으니 공백을 많이 줘서 가독성을 높여도 된다.

 

 

화면상으로는 개행이지만 한 줄로 연결하기

일부 프로그래밍 언어에서는 문자열 등이 길때 역슬래시\ 를 붙이면

명목상으로는 여러줄이지만 실제로는 한 줄로 붙여주는 역할을 한다.

즉, 개행 무시 문자라고 볼 수 있다.

asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf

asdfasdfasdfasdfasdfasdfasdfasdfasdf\
asdfasdfasdfasdfasdfasdfasdfasdfasdf\
asdfasdfasdfasdfasdfasdf

위 2개는 같은 길이의 문자로 간주된다.(\를 쓴 부분은 개행이 일어나도 없는것으로 간주)

셸 스크립트에서도 동일한 맥락으로 \를 사용할 수 있다.

 

rootdir.sh

#!/bin/bash

echo \
		"root"

위의 \로 인해 저 명령어는 ehco; “root”; 의 2개의 문이 아닌 하나의 문인 echo “root”로 간주된다.

\는 셸에서 명령어를 칠 때도 다음줄 내용을 이어서 쓴다는 의미로도 사용된다.

비슷하게 사용되는 파이프라인 문자 | 역시 개행을 무시하고 같은 명령어로 간주한다.

 

 

주석

# 을 붙이면 #의 오른쪽은 전부 주석으로 처리된다.

 

 

변수

셸 스크립트도 일종의 스크립트 구문이므로 변수 등을 사용할 수 있다.

셸 내부에서 사용하는 변수를 셸 변수라고 한다.

 

이런 변수는 저장시에는

변수명=저장할내역

형식으로 사용하며

 

이후 변수 내부 내역을 꺼낼 때는

$변수명

형식으로 해당 변수의 값을 참조해서 쓸 수 있다.

명령프롬포트에서도 바로 사용 가능하다.

 

변수의 값이 아닌 $abcd 문자 자체를 출력하고 싶다면 $ 앞에 탈출문자를 붙여주면 된다.

 

 

quote 이해하기

quote는 따옴표다.

홑따옴표는 변수값을 포매팅에 활용할 수 없지만

쌍따옴표는 변수값을 포매팅에 활용할 수 있다.

 

quotetest.sh

#!/bin/bash

name=chad
echo 'my name is $name'
echo "my name is $name"

위의 코드는 echo가 그냥

my name is $name 을 출력하지만

아래의 코드는

my name is chad 라고 $name이 따옴표 내부에서도 변수 값을 참조해온다.

 

쌍따옴표 내부에서 변수값을 참조하지 않고 $name으로 출력하고 싶다면

\$name 과 같이 탈출문자 \을 활용해 참조목적으로 쓰인 $가 아님을 지정하면 된다.

 

 

명령어 치환

특정한 명령어를 수행한 결과를 파일 이름 등으로 사용하고 싶은 경우가 있다.

이를 수행할때는 $(명령어)를 이용할 수 있다.

 

$ date ‘+%Y-%m-%d’

수행시 yyyy-mm-dd 형식으로 날짜가 나오고 이것을 파일 이름으로 둬야 하는 경우가 있다.

이 때, 날짜는 파일이름으로 만들고 싶다면 아래와 같이 셸 스크립트를 작성한다.

 

today_date.sh

#!/bin/bash

filename=$(date '+%Y-%m-%d')
touch "$filename"

셔뱅을 제외한 첫 번째 줄은 filename변수에

우변의 구문을 실행했을때 나오는 날짜를 변수에 저장한다.

 

그리고 touch를 통해 날짜로 파일을 생성한다.

즉, 콘솔에 찍혔을 값을 우변에 리턴하는 것이다.

 

오늘 날짜로 생성된 파일이 생겼다.

 

 

파라미터 전달하기

셸 스크립트에서는 파라미터의 위치에 따라 $번호 에 해당하는 변수에 대입된다.

 

$ ./parameters.sh aaa bbb ccc

위 구문에서 첫 번째로 사용한

./parameters.sh 는 자동으로 $0으로 간주되고

그 다음인 aaa는 $1

그 다음인 bbb는 $2

그 다음인 ccc는 $3

에 저장되는 식으로 파라미터 순서를 왼쪽부터 0으로 간주한다.

 

parameters.sh

#!/bin/bash

echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo "\$4 = $4"
echo "\$5 = $5"

위와같이 $번호 = 값 을 5번까지 출력하는 파일을 먼저 작성한다.

 

그리고 아래와 같이 실행하면 

$ ./parameters.sh aaa bbb ccc

순서대로 파라미터 값이 들어간 것을 확인할 수 있다.

 

 

인자 개수 확인하기

이렇게 전달된 인자의 개수가 몇 개인지는 $# 으로 조회할 수 있다.

인자의 개수를 출력할 수 있도록 수정한 후

 

다시 실행하면 마지막에 인자의 개수가 잘 출력된다.

 

 

제어문 사용하기

배시에서도 조건분기, 반복처리를 기술할 수 있다.

개념적으로는 완전히 같고 문법만 약간 다르다.

 

if문

if문은 [ 명령어 ] 의 내용이 true로 판단되면 실행할 내용,

그리고 else나 elif가 있다면 첫 줄이 false로 판단되면 실행할 내용을 적는다.

 

if_bin.sh

#!/bin/bash

if [ "$1" = "bin" ]; then
	echo "OK"
else
	echo "NO"
fi

 

위 스크립트에서 $1은 위에서 배운 파라미터의 $1이다.

파라미터로 뭘 주냐에 따라 결과가 다르게 나온다.

 

또한 세미콜론이 있다면 then과 조건식이 같은줄에 놓일 수 있지만

생략했다면 무조건 다음줄로 내려야 한다.

 

작성 시 주의사항

  • 대괄호 양옆으로 한 칸씩 띄어서 작성해야 한다.
  • if문 마지막에는 fi를 작성해야 한다.

 

위와 같이 작성한 뒤

 

셸 스크립트 파일명 옆에 파라미터를 입력하면

bin과 일치하는지 검사 후 OK나 NO를 출력한다.

 

 

명령어의 종료 상태

$ ls # ls명령어를 실행함

$ echo $? # 직전에 실행한 명령어(지금은 ls)의 상태를 조회함
0

기본적으로 명령어는 정상 종료 시 0을 가진다.

그러나 에러가 발생하면 0이 아닌 다른 번호를 가지게 된다.

 

showstatus.sh

#!/bin/bash

ls /
echo "exit ($?)"

ls /test
echo "exit ($?)"

아마 없는 경로를 지정한 2번째 ls는 다른 번호를

root 폴더 조회인 첫 ls는 0이 나올 것이다.

 

ls /은 루트 디렉토리 내의 파일, 디렉토리 목록이 출력되고

ls /test는 루트 밑 test 디렉토리 내의 파일, 디렉토리 목록을 출력하라는 명령어다.

 

셸 스크립트 작성 후 권한을 부여한 뒤 실행해 보면

없는 경로를 입력한 두 번째 ls는 0이 아닌 2가 뜨는 것을 확인할 수 있다.