find

탐색기 명령어

현재 경로부터 확자가 java 인 파일을 모두 검색

sudo find ./ -name "*.java"

파일과 디렉터리 검색

find / -type f
find / -type d

exec 속성을 통해 찾은 파일 혹은 디렉토리에 후속 명령을 날릴 수 있다.

sudo find ./ -name "*.java" -exec ls -l {} \;

뒤에 특수기호 {}, \; 가 들어간다.
{}는 find 명령으로 출력된 결과물 한라인을 뜻한다.
\;는 exec 명령의 끝을 뜻한다.

grep

참고 https://recipes4dev.tistory.com/157?fbclid=IwAR3Wg9anxLkuefISdyC9xCOgNodjhXnyUf8f6Wmf_lKYug9MzzcO_uESUSs

지정된 패턴과 일치하는 문자열이 있는지 파일을 검색하는 데 사용되는 Unix 명령

linux1

유닉스의 텍스트 에디터 g, re, p 3개의 이름에서 유래되었다.

grep '찾을문자열' '파일'

찾을문자열은 정규표현식이 사용될 수 있다.

grep 사용 예 명령어 옵션
대상 파일에서 문자열 검색 grep "STR" [FILE]
현재 디렉토리 모든 파일에서 문자열 검색 grep "STR" *
특정 확장자를 가진 모든 파일에서 문자열 검색 grep "STR" *.ext
대소문자 구분하지 않고 문자열 검색 grep -i "STR" [FILE]
매칭되는 PATTERN이 존재하지 않는 라인 선택 grep -v "STR" [FILE]
단어(Word) 단위로 문자열 검색 grep -w "STR" [FILE]
검색된 문자열이 포함된 라인 번호 출력 grep -n "STR" [FILE]
하위 디렉토리를 포함한 모든 파일에서 문자열 검색 grep -r "STR" *
최대 검색 결과 갯수 제한 grep -m 100 "STR" FILE
검색 결과 앞에 파일 이름 표시 grep -H "STR" *
문자열 패턴 전체를 정규 표현식 메타 문자가 아닌일반 문자로 검색하기 grep -F "*[]?..." [FILE]
색깔 입히기 grep "STR" [FILE] --color=auto

요약
-i : 대소문자 구분x
-v : 해당패턴 제외
-w : 단어 단위
-n : 라인번호 출력
-r : recursive
-H : 파일명 출력
-F : 정규표현식이 아닌 일반문자 취급
-m 100 : 100 line 까지 출력

리다이렉트

명령 출력값을 특정 파일에 저장하려면 아래와 같이 꺽쇠 기호(리다이렉트 연산자)를 사용한다.
command > output.txt

>> 두개를 연달아 사용하면 문서 끝 부분부터 데이터를 덧붙인다.

less-than 연산자 < 를 사용하면 출력과 반대로 입력이 가능하다.
command < input.txt

wc

wc 명령과 같이 사용하면 [line수, word수, byte수] 를 쉽게 알 수 있다.

$wc test.sh
  6  16 102 test.sh

입력 리다이렉트 기호 2개를 연달아 사용하면 인라인 입력을 할 수 있다.

천번째 문자로 입력 시작과 끝을 뜻하는 문자를 입력하고
바로 버퍼에 입력할 후속 문자열들을 입력가능하다.

$ wc << EOF
> test1
> test2
> test3
> EOF
 3  3 18

<< 를 인라인 입력 리다이렉트 기호라 한다.

envsubst

substitutes environment variables in shell format strings

envsubst [OPTION] [SHELL-FORMAT]

다음 문자열을 저장하고 있는 shell_format_test.txt 파일 저장

# shell_format_test.txt
This is $FOO and this $BAR

export 명령어로 환경변수 적용하고 envsubst 명령어로 출력 가능

export FOO=foo export BAR=bar

envsubst < shell_format_test.txt
This is foo and this bar

envsubst '$FOO' < shell_format_test.txt
This is foo and this $BAR

envsubst '$FOO,$BAR' < shell_format_test.txt
This is foo and this bar
# welcome.txt
Hello user $USER in $DESKTOP_SESSION. It's time to say $HELLO!
export HELLO="good morning"
envsubst < welcome.txt
Hello user gojiyong in . It's time to say good morning!

unset HELLO
envsubst < welcome.txt
Hello user gojiyong in . It's time to say !

파이프

한 명령의 출력을 다른 명령의 입력으로 리다이렉트 하는 과정을 파이프라 한다.
아래와 같이 grep, more 같은 명령과 자주 사용된다.

$ netstat -antp | grep 8080
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      19187/beam.smp

파이프는 2개의 명령을 연속으로 실행하지 않고 리눅스 내부 시스템에서 2개의 명령을 결합하고 동시에 실행시킨다.
따라서 중간파일 혹은 출력 저장용 버퍼가 별도로 생성되지 않는다.

환경변수

bash 쉘에는 2가지의 환경변수가 있다.

  1. 전역변수
  2. 지역변수

전역 환경변수

env, printevn 명령으로 확인 가능

특정 환경변수만 보고싶다면 아래 명령어를 참고
printevn 'HOME'
echo $HOME

전역 환경변수 정의

export key=value 명령으로 정의가능하다.

$ export MY_VARIABLE="hello world"
$ echo $MY_VARIABLE
hello

띄어쓰기가 들어간다면 쌍따옴표로 묶어주자.
전역변수는 대문자, 지역변수는 소문자로 정의하는 것이 사용자간 약속이다.

정의해둔 전역변수는 자식쉘에서 접근이 가능하다.

전역 환경변수 생명주기

전역변수라고 하지만 해당 쉘에만 유효하지 자식이 아닌 다른 쉘에게는 유효하지 않다.
또한 자식쉘이 전역변수를 생성하거나 부모쉘이 이미 정의한 전역변수를 변경한다 하더라도 부모쉘에게는 유효하지 않다.

쉘이 종료되면 삭제되며 unset 과 같은 명령으로도 삭제가능하다.

지역 환경변수

지역 환경변수만을 출력하는 명령어는 없다.
set 명령을 사용하면 전역,지역 환경변수를 모두 정렬 출력해준다.

지역 환경변수 정의

export 없이 등호를 사용해 정의

$ my_variable=hello
$ echo $my_variable
hello

지역 환경변수 생명주기

해당 지역 환경변수를 선언한 쉘이 종료되면 사라진다.

또한 부모 쉘에서 자식 쉘이 선언한 지역변수는 접근 가능하지만 자식 쉘에서 부모 쉘의 지역변수는 접근 불가능하다.

전역변수와 마찬가지로 쉘이 종료되거나 unset 명령으로 삭제가능하다.

지역이던 전역이던 생성된 프로세스에 종속된다.

환경 변수배열

변수형대로 환경변수를 정의할 수 있다.

$ mytest=(one two three four five)
$ echo mytest
one
$ echo ${mytest[2]}
two
$ echo ${mytest[*]}
one two three four five
$ mytest[2]=투
one 투 three four five

시스템 환경변수

printevn 또는 env 명령을 통해 이미 할당되어있는 환경변수를을 확인 가능하다.
리눅스 시스템에선 이미 많은 종류의 환경변수가 정의되어 있고 이를 통해 사용자 환경을 구축한다.

우리가 흔히 사용하는 PATH 환경변수도 이중 하나이다.

지금까지 프로그램 실행을 위해 아래 명령어로 PATH 환경변수를 확장해 나갔다.

$ PATH=$PATH:"새로 추가할 path" 지역변수 PATH를 정의하고 전역변수 PATH + 우리가 새로 추가할 내용을 더해 지역변수 PATH에 삽입한다.

지역변수이기에 해당 쉘이 종료되면 더이상 사용할 수 없다.
이를 해결하기 위해 로그인 작업이 일어날때 쉘이 어떤 역할을 하는지 알아서 자동으로 추가해보자.

  1. /etc/profile
    bash 쉘의 기본 시동파일, 로그인시 모든 사용자가 해당 파일을 사용한다.
    우분투의 경우 /etc/bash.profile에 등록된 환경변수들을 익스포트한다.
    또한 /etc/profile.d 디렉토리 안에 있는 모든 파일을 차례대로 실행한다.

  2. $HOME/.bash_profile
  3. $HOME/.bashrc
  4. $HOME/.bash_login
  5. $HOME/.profile
    $HOME으로 시작하는 시동파일 4개가 있다. $HOME/.bash_profile, $HOME/.bash_login, $HOME/.profile 3개중 먼저 감지되는 파일 하나만 실행된다.

    보통 .bash_profile 하나만 있다.

즉 로그인할 때마다 전역변수를 추가하고 싶다면 위의 시동파일을 수정하거나 시동파일이 실행하는 파일을 추가하면 된다.

바람직한 방법으론 시동파일이 실행하는 ~/.profile 에 환경변수 추가 명령을 작성하는 것.

#JAVA
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home

#MAVEN
export M3_HOME=/usr/local/bin/mvn

#Android-react
export ANDROID_HOME=$HOME/Library/Android/sdk

aptitude & dpkg

apt 혹은 dpkg 로 패키지 설치 및 관리를 하였는데 aptitude 를 사용하면 좀더 사용자 친화적인 환경에서 패키지 관리가 가능하다.

일단 설치

$ sudo apt-get update
$ sudo apt-get install aptitude

$ aptitude 명령으로 실행시키면 대화형 콘솔창을 통해 설치된 패키지 목록이 가능하다.

linux2

aptitude show 'pakage_name' - 설치된 패키지 확인.
aptitude search 'package_name' - 설치할 패키지 조회.

linux3

aptitude install vim - 설치명령

root@ubuntu:/# aptitude install vim
The following NEW packages will be installed:
  file{a} libexpat1{a} libgpm2{a} libmagic1{a} libmpdec2{a} libpython3.5{a} libpython3.5-minimal{a} libpython3.5-stdlib{a} mime-support{a} vim vim-common{a} vim-runtime{a}
0 packages upgraded, 12 newly installed, 0 to remove and 4 not upgraded.
Need to get 10.8 MB of archives. After unpacking 53.9 MB will be used.
Do you want to continue? [Y/n/?] y
Get: 1 http://archive.ubuntu.com/ubuntu xenial/main amd64 libgpm2 amd64 1.20.4-6.1 [16.5 kB]
...
...

설치에 연관되는 부가적인 패키지 까지 모두 같이 설치된다.

설치 확인을 위해 aptitude search vim

linux6

앞에 i가 붙어있는데 이미 설치된 패키지임을 뜻한다.

aptitude search '!~i bash' - 이미 설치된 패키지만 확인

가장 일반적인 상태는 p입니다. 이는 시스템에 패키지의 흔적이 없음을 의미합니다.
c는 패키지가 삭제되었지만 구성 파일은 시스템에 남아 있으며 i는 패키지가 설치되었음을 의미하고
v는 패키지가 가상임을 의미합니다. 세 번째 문자가 A이면 패키지가 자동으로 설치된 것입니다.
virtual package: https://www.debian.org/doc/manuals/debian-faq/ch-pkg_basics.en.html#s-virtual

aptitude purge 'pakage_name' - 설치된 패키지 삭제

dpkg -L 'package_name' 패키지와 관련된 파일목록 확인

linux4

dpkg --search 'file_name'파일과 관련된 패키지 확인

linux5

vi 명령어 모음

참고 https://blog.outsider.ne.kr/540

일반모드: 막 시작한 상태, 커서이동 가능
입력모드: 텍스트 입력하는 모드
명령행모드: vi실행 명령 입력가능한 모드

커서 이동

일반모드에서 이동키 앞에 숫자를 붙이면 그만큼 이동함

66↓, 66j 입력시 66칸 아래로 이동

명령모드에서 줄번호 입력 :1, :66

일반모드에서 이동

^ - 문장의 맨 앞
$ - 문장의 맨 뒤
0 - 라인 맨 앞
gg - 문서첫줄
G - 문서막줄
% - 괄호 반대짝으로 이동

b - 현재 단어의 첫글자로 이동, 이미 첫글자라면 이전단어의 첫글자로 이동
e - 현재 단어의 끝으로 이동, 이미 끝이라면 다음 단어의 끝으로 이동
w - 무조건 다음 단어의 첫글자로 이동
ge - 무조건 이전 단어의 끝으로 이동

f'문자' - find ‘문자’, 해당 문자로 이동(문장 앞에서 문자를 찾음)
F'문자' - 해당 문자로 이동(문장 뒤로 문자를 찾음)

*, # - 현재 단어를 포워드/백앤드 방향으로 찾음

v - 비쥬얼모드(비쥬얼 모드에서 커서 이동해서 블럭지정 가능) y - 복사하기 c - 잘라내기

복붙/삭제

:n,my - n 줄부터 m 줄까지 복사
:%y - 모두 복사

행 이동에서 사용했던 단축키를 그대로 사용한다.

y^ - 문장 맨 앞까지 복사
y$ - 문장 맨 뒤까지 복사
y0 - 라인 맨 앞까지 복사
ygg - 현재커서부터 첫 라인까지 복사
yG - 현재커서부터 마지막 라인까지 복사

삭제의 경우 yd로만 바꾸어주면 그대로 동작한다.

cw - 현재커서에서 단어 잘라내기

멀티탭

:new - 가로로 분할된 창 열기 :vs - 세로로 분할된 창 열기 Ctrl + w - 분할창 간에 이동하기 :tabnew - 새로운 탭 열기 :gt - 다음 탭으로 이동하기 :gT - 이전 탭으로 이동하기 :e ./ - 현재 탭에 오픈할 파일 탐색하기( ./ 는 현재위치에서 탐색 시작)

찾기/변경

:/'찾을문자열' - 일치하는 첫번째 위치로 커서이동

next를 뜻하는 n 단축키로 다음 위치로 이동가능

:s/'찾을문자열'/'변경문자열' - substitute 를 뜻하는 s를 앞에 붙여 변경 가능하다. 시작 위치에서 첫번재 검색내용을 변경한다.

:%s/'찾을문자열'/'변경문자열/g' - 전체 문서에서 찾은 모든 내용을 변경한다.
:%s/'찾을문자열'/'변경문자열/gc' - 전체 문서에서 찾은 모든 내용을 사용자에게 물어보고 변경한다.

undo redo

u : 실행취소
5u : 5번 실행취소

ctrl+r : 재실행
5ctrl+r : 5번 재실행

쉘 스크립트

항상 쉘 스크립트를 작성할 때 맨 윗부분에 실행되는 쉘 종류를 주기한다.

# !/bin/bash

echo

echo 명령어는 쉘과 사용자같의 대화법이다.

다음과 같은 특성을 가지고 있다.

$ echo hello world
 hello world
$ echo "hello Let's play the world"
 hello Let's play the world
$echo 'hello Let"s play the world'
 hello Let"s play the world
$echo "hello Let\"s play the world"
 hello Let"s play the world

띄어쓰기가 포함되어도 하나의 문자열로 인식한다.

스크립트 변수

스크립트 내에서 환경변수를 사용할 수 있다.

아래와 같은 스크립트 파일을 생성하고 실행해보자.

# !/bin/bash
echo "user info for hostname: $HOSTNAME"
echo "UID: $UID"
echo "HOME: $HOME"
# chmod u+x test.sh
# ./test.sh 
user info for hostname: ubuntu
UID: 0
HOME: /root

스크립트 내에서 사용자변수 생성도 가능하다.

# !/bin/bash

days=10
guest="Katie"
echo "$guest checked in $days days ago"
days=5
guest="jessica"
echo "$guest checked in $days days ago"
결과값
Katie checked in 10 days ago
jessica checked in 5 days ago

변수에 문자열을 할당하는 것과 다른 변수의 데이터를 할당하는 것을 구분해야한다.

# !/bin/bash

value1=10
value2=value1
echo "value2 = $value2"
value2=$value1
echo "value2 = $value2"
value2=\$value1
echo "value2 = $value2"
결과값
value2 = value1
value2 = 10
value2 = $value1

변수에 명령어로 얻은 결과값을 삽입할 수 있다.

# !/bin/bash

date=$(date)
echo "The date and time are $date"
결과값
The date and time are Tue Feb 18 09:54:45 UTC 2020

# echo $(date) 이런 명령어도 똑같이 작동하기 때문에 $(...) 안에 명령어가 들어가고 반환문자열이 들어간다 생각하면 된다.

echo $(date +%y%m%d) - date 명령 뒤에는 날짜 포멧을 지정할 수 있다.
출력값: 200218

이를 사용해 현재 날짜에 해당하는 로그파일을 생성하는 스크립트를 작성하자.

# !/bin/bash

today=$(date +%y%m%d)

echo "The date and time are $today"
ls /usr/bin -al > log.$today

디렉터리에 날짜에 해당하는 로그파일이 생겼는지, ls명령의 결과값이 담겼는지 확인하자.

스크립트에서 시스템 명령을 사용하기 위해 서브쉘을 생성하고 명령을 수행한다. 부모가 만든 (환경)변수는 자식에게 공유되지 않기에 서브쉘에선 변수를 사용하지 못한다.
단 위의 ls와 같이 내장 쉘 명령이나 경로없이 사용하는 경우에는 서브쉘이 만들어지지 않는다.

if-then

다른 언어에서의 if-else 역할을 하는 구문

# !/bin/bash

if pwd
then
	echo "it worked"
fi
결과값
/root
it worked

if문 다음에 오는 명령의 exit 코드를 판별해 then 아래의 명령을 수행할지 결정한다.

# !/bin/bash

if abracadabra
then
	echo "it worked"
fi

당연히 동장하지 않는 명령어를 넣으면 then 아래의 명령은 수행되지 않는다.

결과값
./test.sh: line 3: abracadabra: command not found

else

당연히 else 구문도 존재한다.

testUser=gojiyong

if grep $testUser /etc/passwd
then
	echo "this is my first command"
	echo "this is my second command"
	echo "I can even put in other commands bediseds echo:"
	ls -a /home/$testUser/.b*
else
  echo "The user $testUser dose not exist on this system"
  echo
fi

gojiyong란 유저계정은 생성하지 않았기에 else 아래 명령문이 수행된다.
else 밑에 then 이 없는것에만 주의하자.

결과값
The user gojiyong dose not exist on this system

elif

else if 의 약자

# !/bin/bash

username1=test
username2=timed
if grep $username1 /etc/passwd; then
	echo "if command success"
elif grep $username2 /etc/passwd; then
    echo "elif command success"
else
    echo "no match user"
fi

if, elif 둘다 then 을 사용해야 하는것에 주의, 또한 뒤에 ; 을 사용하면 다른언어와 같이 한줄에 if문 처리가 가능하다.

test

if, elif 가 쉘 명령의 exit 코드를 기반으로 참 거짓을 판별했었다.

쉘 스크립트에선 exit 코드 외에는 if-elif-then 구문을 사용할 수 없기에 여러가지 쉘 명령을 통해 검사 데이터의 true, false 여부를 판단한다.

test 는 변수에 데이터가 있는지 없는지 판단하는 쉘 명령이다.

$ test ""
$ echo $?
 1
$ test "test"
$ echo $?
 0

test 뒤에 값 유무에 따라 exit(0 or 1) 코드를 반환하기에 쉘 스크립트에서 요긴하게 사용할 수 있다.

# !/bin/bash

name=""
if test $name ; then
	echo "my name is $name"
else
    echo "no user name"
fi
결과값
no user name

name을 공백으로 넣었기 때문에 test 명령의 exit 코드는 1이 되고 else문이 실행된다.

if 문에서 test 문자가 들어가는 것이 어색하다면 [ , ] 대괄호로 대체 가능하다.

# !/bin/bash

name=""
if [ $name ] ; then
	echo "my name is $name"
else
    echo "no user name"
fi

주의할점은 대괄호와 내용 사이에 반드시 공백이 있어야 한다.

test 명령은 단순 값의 유무만 판단할 뿐 아니라 비교연산도 가능하다.

$ test 1 -eq 2
$ echo $?
 1
$ test 1 -lt 2
$ echo $?
 0
비교 설명
n1 -eq n2 n1n2equal 인지 검사한다.
n1 -ne n2 n1n2not equal 인지 검사한다.
n1 -ge n2 n1n2greater or equal 인지 검사한다.
n1 -gt n2 n1n2greater than 인지 검사한다.
n1 -le n2 n1n2less or equal 인지 검사한다.
n1 -lt n2 n1n2less than 인지 검사한다.
str1 = str2 str1str2 와 같은지 검사한다.
str1 != str2 str1str2 와 같지 않은지 검사한다.
str1 \< str2 str1str2 와 같은지 검사한다.
str1 \> str2 str1str2 보다 큰지 검사한다.
-z str str 길이가 0보다 큰지 검사한다.
-n str str 길이가 0인지 검사한다.

이럴꺼면 숫자 비교도 등호식으로 해주지…

부등호는 리다이렉트로 인식되지 않게 이스케이프 처리 필요
또한 비교는 ASCII 순서를 기준으로 하기에 sort 명령과 반대이다. 대문자가 소문자보다 작은것으로 판별된다.

test 의 파일비교

쉘 스크립트에서 가장 많이 사용되는 판별이 파일(디렉토리) 검사이다.

-e file is exitst?
-d file is exitst and directory?
-f file is exitst and file?
-r file is exitst and readable?
-w file is exitst and writeable?
-x file is exitst and executable?
-O file is exitst and current user ownership?
-G file is exitst and current user group?
file1 -nt file2 is file1 newer than file2?
file1 -ot file2 is file1 older than file2?

연산

사칙연산을 위해 expr(Expression) 명령을 사용할 수 있다.

사칙연산, 비교연산

$ expr 2 + 1
3

$ expr 2 - 1
1

$ expr 2 / 1
2

$ expr 2 \* 1
2

$ expr 3 % 2
1

$ expr 3 \< 2
0

$ expr 3 \> 2
1

$ expr 2 \<= 2
1

$ expr  2 = 3
0

$ expr  2 != 3
1

거짓은 0으로 참은 1로 반환한다.
참고로 bash 쉘 연산은 정수만 지원한다.

$ expr 3 / 2
1

특정 문자에는 \ 을 붙여야 동작한다. 혹은 특수문자를 홀따옴표나 쌍따옴표로 감싸도 된다.

AND, OR 연산자

|(OR) 연산자 - 두개의 값중 0이나 null이 아닌 값을 반환
둘다0, null이 아니라면 첫번째 값을 반환

$ expr 0 \| 0
0
$ expr 0 \| 2
2
$ expr 2 \| 3
2

&(AND) 연산자 - 두 값이 0이나 null이 아닌지 확인
둘다 0, null이 아니라면 첫번째 값을 반환

$ expr 0 \& 0
0
$ expr 0 \& 2
0
$ expr 2 \& 3
2

문자열 연산자

문자열 자르기

$ expr substr helloworld 3 5
llowo

index 검색

$ expr index helloworld w
6
$ expr index helloworld t
0

length구하기

$ expr length helloworld
10

쉘 스크립트 내에서 연산

사용자 변수에 대입도 가능하다.

$ var3=$(expr 1 + 2)
$ echo var3
var3

아래와 같은 형식으로 쉘 스크립트 안에서도 연산가능하다.

# !/bin/bash

var1=10
var2=20
#var3=$var1+$var2
var3=$(expr $var1 + $var2)
echo The result is $var3
결과값
The result is 30

expr 대신 주석과 같이 연산처리 한다면 The result is 10+20 이 출력된다.

bash 쉘에선 expr도 호환되지만 대괄호를 사용해 대체할 수 있다.

$ var3=$[1 + 2]
$ echo $var3
3

부동 소수점 연산

bash쉘 내장 계산기 bc 를 사용하면 된다.

$  bc -q
3.156*(3+2)
15.780
quit

-q 는 환영문 출력 x

나눗셈의 경우 소수점 표현을 위해 스케일서정을 해주어야 한다.
또한 등호를 통해 변수정의가 가능하다.

$ bc -q
3.48/7
0

scale=5
3.48/7
.49714

var1=3.48
var2=var1 * 5

print var2
17.40

쉘 스크립트에서 사용하려면 echo, 파이프, bc 를 통해 사용 가능하다.

# !/bin/bash

var=$(echo "scale=4; 3.44 / 7" | bc)
echo The answer is $var
결과값
The answer is .4914

bc에서 복잡한 수식을 처리해야 한다면 인라인 리다이렉트 연산자로 처리해보자.

# !/bin/bash

var1=10.46
var2=43.67
var3=33.2
var4=66
var5=$(bc << EOF
a1=($var1 * $var2)
b1=($var3 * $var4)
a1 + b1
EOF
)

당연히 a1, b1에 대한 값은 스크립트에서 재사용 불가능하다.

결과값
The final answer is 2647.98

쉘 종료코드 - exit

쉘은 명령을 실행하면 항상 결과값을 리턴받는다.

$ abracadabra
bash: abracadabra: command not found
$ echo $?
127

0은 성공, 1~255 는 오류코드로 인식한다.

코드 설명
0 명령이 성공적으로 완료됨
1 일반 알 수 없는 오류
2 쉘 명령을 잘못 사용함
126 명령을 실행할 수 없음
127 명령을 찾을 수 없음
128 잘못된 종료 매개변수
128+ 치명적 오류로 리눅스 신호 x를 뜻함
130 Ctrl+c로 명령이 종료됨
255 범위를 벗어난 상태

우리가 작성한 쉘 스크립트도 성공적으로 종료되면 0, 실패하면 에러코드를 반환하도록 설정하자.

exit 명령을 통해 반환값을 지정할 수 있다.

# !/bin/bash

val=10
echo Value=$val
exit 1
$ ./test.sh
Value=10
$ echo $?
1
$ cat FILE.txt
  airplane
  apple
  banana
  bird
  cat
  pineapple
$ grep horse FILE.txt
$ echo $?
  1
$ grep cat FILE.txt
  cat
$ echo $?
  0

주의사항: 반환값이 255 이상일 경우 255로 나눈 나머지값이 반환된다.