프로그램을 실행할 때 인자(매개변수)를 전달하듯, 쉘 스크립트 역시 인자를 전달하여 실행할 수 있다.
이때, 스크립트 내에서 해당 인자를 받았을 때 처리하는 로직이 필요한데, 그러한 로직을 짤 때, '$'가 다양하게 쓰일 수 있다! 아래는 'test.sh' 라는 쉘 스크립트 파일을 실행하면서 a,b,c,d 라는 인자를 준 상황이다.
./test.sh a b c d
# './test.sh' 가 $0에 해당.
# 'a' 가 $1에 해당.
# 'b' 가 $2에 해당.
# 'c' 가 $3에 해당.
# 'd' 가 $4에 해당.
쉘 스크립트에서의 '$' 의 활용 - 위치 매개 변수(Positional Parameters)
종류 | 설명 |
$0 | 실행된 쉘 스크립트의 메인 구문 |
$1 | 스크립트에 넘겨진 첫 번째 아규먼트 |
$2 | 스크립트에 넘겨진 두 번째 아규먼트 |
$N(숫자) | 해당 숫자에 해당하는 N 번째 아규먼트 |
$# | 아규먼트의 개수를 의미 |
$* | 스크립트에 전달된 인자 전체를 하나의 변수에 저장하면, IFS 변수의 첫 번째 문자로 구분된 결과를 의미. |
$@ | $*와 동일하지만, IFS환경변수를 사용 X |
$! | 실행을 위해 백그라운드로 보내진 마지막 프로그램 프로세스 번호 |
$$ | 쉘 스크립트의 PID |
$? | 바로 이전 스크립트 또는 명령문 실행 뒤의 반환 값 (백그라운드로 실행된 것은 제외) |
실제 쉘 스크립트의 실행을 통해 어떻게 동작하는지 살펴보자!
#! /bin/sh
# 해당 쉘 스크립트의 파일 명 : test_junho.sh
echo "##############################"
echo
echo -e "main_command(\$0) : $0"
echo -e "\$1 : $1"
echo -e "\$2 : $2"
echo -e "\$# : $#"
echo -e "\$* : $*"
echo -e "\$@ : $@"
echo -e "\$$ : $$"
echo "##############################"
위 쉘 스크립트의 디렉토리로 이동하여 실행 명령으로 './test_junho.sh a b c' 를 입력하면 아래와 같은 결과를 확인할 수 있다.
위 결과를 보면 위치 매개 변수가 무엇을 의미하는지 대강 알 수 있을 것이다.
그런데 여전히 $*, $@, $! 등은 잘 이해가 가지 않을 수 있다. for 문을 활용한 아래 예시를 보며, 구체적으로 확인해보자!
1) $* 을 for문에서 사용한다면?
#! /bin/sh
set 'a b' c d # 이 쉘 스크립트의 실행 매개변수를 'a b', 'c', 'd' 로 지정.
echo "##############################"
echo
echo -e "What is '\$*'" # \ 는 이스케이프 문자
n=1
for i in $* # '$*' 를 그대로 사용하였을 때.
do
echo "for #$n : $i"
n=$((n + 1))
done
echo
echo "##############################"
echo
echo -e "Using Double Quotation -> \"\$*\"" # \ 는 이스케이프 문자
n=1
for i in "$*" # 큰 따옴표를 사용한 "$*" 의 활용
do
echo "for #$n : $i"
n=$((n + 1))
done
echo
echo "##############################"
우선 $* 는 매개변수를 받은 것들을 모두 한 변수에 넣고 IFS로 구분하게 된다. 즉, $*를 기준으로 for문을 수행하면, IFS의 디폴트값인 공백을 기준으로 매개변수를 쪼개어 하나씩 for문을 수행하게 된다. .
그런데 큰 따옴표를 사용하여 "$*" 를 기준으로 for문을 수행하면, 각 매개변수들을 모두 이어 붙인 것을 하나의 문자열로 인식하기 때문에, 아래 결과처럼 for 문이 한 번만 수행되게 되는 것이다.
2) $@ 을 for문에서 사용한다면?
#! /bin/sh
set 'a b' c d # 이 쉘 스크립트의 실행 매개변수를 'a b', 'c', 'd' 로 지정.
PRE_IFS=$IFS
IFS=':' # IFS를 : 로 변경 -> ':' 를 구분자로 사용하겠다.
echo "##############################"
echo
echo -e "What is '\$@'" # \ 는 이스케이프 문자
n=1
for i in $@ # '$@' 를 그대로 사용하였을 때.
do
echo "for #$n : $i"
n=$((n + 1))
done
echo
echo "##############################"
echo
echo -e "Using Double Quotation -> \"\$@\"" # \ 는 이스케이프 문자
n=1
for i in "$@" # 큰 따옴표를 사용한 "$@" 의 활용
do
echo "for #$n : $i"
n=$((n + 1))
done
IFS=$PRE_IFS # IFS 원상 복구 (반드시 해주어야 함.)
echo
echo "##############################"
$@ 는 $*와 동작 방식은 거의 같지만, 한 가지 차이점으로 IFS를 사용하지 않는다고 하였다. $@ 는 IFS를 사용하는 것이 아닌, 매개변수를 입력하는 시점에서의 공백 기준으로 자르기 때문에 아래와 같은 실행 결과가 나타난다.
또한 큰 따옴표를 쓴 "$@" 의 경우에서도, 큰 따옴표의 유무와 관련 없이 $@의 동작을 그대로 수행하게 된다.
3) $! 확인 방법
#! /bin/sh
echo "##############################"
echo
echo -e "What is '\$!'" # \ 는 이스케이프 문자
echo
echo -e "This process's PID : $$"
sleep 10
echo "After 10 seconds, finished!!"
echo -e "\$! : $!"
echo
echo "##############################"
위 스크립트를 수행할 때, 스크립트의 디렉토리로 가서 '/test_junho.sh &' 로 입력하여 백그라운드로 실행시켜 주면,
해당 스크립트로 실행된 프로세스의 PID($$의 결과)가 25512 인 것을 확인할 수 있다.
여기서 주의할 점은, 이 스크립트가 실행되는 동안(백그라운드)의 $! 값을 조회하면 아무것도 나타나지 않는 반면,
해당 스크립트의 백그라운드 실행을 빠져나와서 'echo $!' 를 입력하면, 해당 프로세스의 PID인 25512 를 확인하 수 있게 된다는 것이다.
4) $? 의 사용
만약 명령어가 실패할 경우 동작을 다르게 하려고 한다면, 스크립트에서는 어떻게 구현해야 할까?
이때 사용하는 것이 $? 이다. $? 는 가장 최근 실행한 명령어의 종료 코드 값이 들어있다. 정상적인 종료는 0으로 반환되며, 리눅스의 일반 명령어의 경우, 비정상 종료가 되면 1을 반환한다. 그 밖의 다른 프로그램의 경우에는, 해당 프로그램에서 설정된 exit(n) 구문에서의 n 값과 같은 종료 코드 값이 들어가게 된다.
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[]){
if(argc<2) {
fprintf(stderr, "인자는 2개 이상이어야 합니다.\n");
exit(16);
}
}
다음 예시를 통해 살펴보자. 위와 같은 c언어로 작성된 프로그램(main.c)이 있다고 생각해보자.
그리고 아래의 쉘 스크립트를 수행한다고 보자.
#! /bin/bash
function func() {
./a.out # 위 C언어로 작성된 프로그램이 컴파일된 파일을 실행하는데, 파라미터 2개를 넘겨주지 않음.
echo "오류 코드 : $?"
}
# 함수 호출
func
위 쉘 스크립트를 수행하게 되면, C언어에서 설정한 종료코드인 16을 출력하는 것을 확인할 수 있을 것이다!
참고
https://bebeya.tistory.com/2696
https://reakwon.tistory.com/136
https://jhnyang.tistory.com/153
'OS > Linux' 카테고리의 다른 글
[Linux][CentOS 7] vi, vim 테마(colorscheme) 설정 - onehalf (0) | 2023.03.08 |
---|---|
[Linux] CentOS 7 에서 User 생성(useradd)과 User 홈 디렉토리 설정 (0) | 2023.02.28 |
정규표현식(Regex)의 개념과 기초 문법 (0) | 2022.08.23 |
[Linux] 쉘 스크립트 - 파일 존재 여부 확인하기! (0) | 2022.08.17 |
[Linux] ps 결과 항목 설명 및 유용한 ps 예제 (0) | 2022.03.25 |
최근댓글