티스토리 뷰

Bash

killog 2021. 6. 24. 13:16
반응형

첫 시작은 문자 출력하기(Hello World)

고전적이지만 "hello world" 단순출력부터 시작해보자. 파일 명을 hello.sh 로 만들고 실행해보자.

안되면 퍼미션을 변경해야하는데 뭔지 모르면 chmod 700 hello.sh 를 해보다.

참고: echo : 문장을 출력하는데 자동으로 줄바꿈됨
printf: C 언어랑 비극함.

주석(Comments)

# 기호로 시작하면 주석이다.마자

함수(Function)

형식은 다른 언어와 차이가 없다. 그러나 function 은 생략해도된다.

함수명을 쓰면 함수가 호출되는데, 주의할 것은 호출코드가 함수코드보다 반드시 뒤에 있어야한다.

string_test(){
        echo "string test"
}
function string_test2(){
    echo "string test 2"
    echo "인자값: ${@}"
}

string_test
string_test2

# 함수에 인자값 전달하기 (공백으로 띄어서 2개의 인자값 넘기기 )
string_test2 "hello" "world"

변수(Variable)

변수 사용시에는 "=" 기호 앞뒤로 공백없이 입력하면 대입연산자가 된다.

그리고 선언된 변수는 기본적으로 전역변수이다. 단 함수 안에서만 지역변수를 사용할 수 있는데, 사용하려면 변수 명 앞에 local 을 붙여주면 된다.
그런데 전역 변수는 현재 실행된 스크립트 파일에서만 유효하다. 자식 스크립트에서는 사용할 수 없는 변수이다.

변수 명 앞에 export 을 붙여주면 환경변수로 설정되어 자식스크립트에서 사용 가능하다. 환경변수 사용시 예약 변수에 주의하자. (참고로 환경 변수는 .bash_profile 에서 정의한다. )

# 전역변수 지정
string="hello world"
echo ${string}

# 지역 변수 테스트 함수
string_test(){
  # 전역 변수와 동일하게 사용한다. 만약, local 이 빠진다면 전역 변수에 덮어 씌워지게 된다.
  local string="local"
  echo ${string}
}

# 지역 변수 테스트 함수 호출
string_test
# 지역 변수 테스트 함수에서 동일한 변수 명을 사용했지만, 값이 변경 안됨.
echo ${string}

# 환경 변수 선언
export hello_world="hello world..."
# 자식 스크립트 호출은 스크립트 경로를 쓰면 된다.
/home/export_test.sh

# 환경 변수를 테스트하기 위해 export_test.sh 파일로 만들고 선언한 변수를 확인해본다.
echo ${hello_world}

예약 변수(Reserved Variable)

문자 설명
HOME 사용자의 홈디렉토리
PATH 실행 파일을 찾을 경로
LANG 프로그램 사용시 기본 지원되는 언어
PWD 사용자의 현재 작업중인 디렉토리
FUNCNAME 현재 함수 이름
SECONDS 스크립트가 실행된 초 단위 시간
SHLVL 쉘 레벨(중첩된 깊이를 나타냄)
SHELL 로그인해서 사용하는 쉘
PPID 부모 프로세스의 PID
BASH BASH 실행 파일 경로
BASH_ENV 스크립트 실행시 BASH 시작 파일을 읽을 위치 변수
TMOUT 0이면 제한이 없으며 time시간 지정시 지정한 시간 이후 로그아웃

위치 매개변수(Positional Parameters)

문자 설명
$0 실행된 스크립트 이름
$1 $1 $2 $3 ... ${10} 인자 순서대로 번호가 부여된다. 10번째부턴 {} 로 감싸줘야함
$* 전체 인자 값
$@ 전체 인자 값($* 동일하지만 쌍따옴표로 변수를 감싸면 다른 경과 나옴)
$# 매개변수의 총 개수

특수매개변수(Special Parameters)

문자 설명
$$ 현재 스크립트의 PID
$? 최근에 실행된 명령어, 함수, 스크립트 자식의 종료 상태
$! 최근에 실행한 백그라운드(비동기)명령어의 PID
$- 현재 옵션 플래그
$_ 지난 명령의 마지막 인자로 설정된 특수 변수

배열(Array Variable)

배열 변수 사용은 반드시 괄호를 사용해야한다. (예. {array[1]})
참고: 1차원 배열만 지원한다.

# 배열의 크기 지정 없이 배열 변수로 선언
# 참고 : 'declare -a' 명령으로 선언하지 않아도 배열 변수 사용 가능하다.
declare -a array

# 4개의 배열 값 지정
array=("hello" "test" "array" "world")

# 기존 배열에 1개의 배열 값 추가(순차적으로 입력할 필요 없음)
array[4] ="variable"

# 기존 배열 전체에 1개의 배열 값을 추가하여 배열 저장(배열 복사시 사용)
array =($(array[@]) "string")

# 위에서 지정한 배열 출력
echo "hello world 출력 :  ${array[0]}  ${array[3]}"
echo "배열 전체 출력 : ${array[@]}"
echo     "배열 전체 개수 출력 : ${#array[@]}"


printf "배열 출력 : %s\n" ${array[@]}

# 배열 특정 요소만 지우기
unset araay[4]
printf "배열 출력 : %s\n" ${array[@]}

# 배열 전체 지우기
unset array
printf "배열 출력 : %s\n" ${array[@]}
array_name=("value 1" "value 2" "value 3")

echo "array_name[0]  =${array_name[0]}" 
echo "array_name[2]  =${array_name[2]}"
echo "array_name[*]  =${array_name[*]}" # print array_name all time
echo "array_name[@]  =${array_name[@]}" # print array_name all time
echo "array_name index  =${!array_name[@]}" # print array_name index number
echo "array_name size  =${#array_name[@]}" # print array_name size
echo "array_name[0] size=${#array_name[0]}" #print array_name[0] size

# 크기 구하기
echo ${#array_name[@]} # print 3



array_name=("value 1" "value 2" "value 3")
echo "array = ${array_name[@]}"
# 출력 결과
# array = value 1 value 2 value 3
printf "value = %s\n" "${array_name[@]}"
# 출력결과
# value = value 1
# value = value 2
# value = value 3

for value in "${array_name[@]}"; do
    echo $value
done

# 출력결과
# value 1
# value 2
# value 3

for (( i=0 ; i< ${#array_name[@]}; i++})); do
    echo "value[$i] = ${array_name[$i]}"
done
# 출력결과
# value[0] = value 1
# value[1] = value 2
# value[2] = value 3

for index in ${!array_name[*]}; do
    prinf "%4d: %s\n" "$index" "${array_name[$index]}"
done
# 출력 결과
#   0: value 1
#   1: value 2
#   2: value 3

파일 비교(File test operators)

문자 설명
-e 파일이 존재
-f 파일이 존재하고 일반 파일인 경우(디렉토리 혹은 장치파일이 아닌 경우)
-s 파일이 존재하고 0보다 큰 경우
-d 파일이 존재하고 디렉토리인 경우
-b 파일이 존재하고 블록장치 파일인 경우
-c 파일이 존재하고 캐릭터 장치 파일인 경우
-p 파일이 존재하고 FIFO인 경우
-h 파일이 존재하고 한 개 이상의 심볼릭 링크가 설정된 경우
-L 파일이 존재하고 한 개 이상의 심볼릭 링크가 설정된 경우
-S 파일이 소켓 디바이스인 경우
-t 파일이 디스크립터가 터미널 디바이스와 연관이 있음
-r 파일이 존재하고 읽기 가능한 경우
-w 파일이 존재하고 쓰기가 가능한 경우
-x 파일이 존재하고 실행 가능한 경우
-g 파일이 존재하고 SetGID가 설정된 경우
-u 파일이 존재하고 SetUID가 설정된 경우
-k 파일이 존재하고 스티키 비트(Sticky bit)가 설정된 경우
-O 자신이 소유자임
-G 그룹 아이디가 자신과 같음
-N 마지막으로 읽힌 후에 변경 됐음
file1 -nt file2 file1 파일이 file2 파일보다 최신임
file1 -ot file2 file1 파일이 file2 파일보다 예전것임
file1 -ef file2 file1 파일과 file2 파일이 같은 파일을 하드 링크하고 있음
! 조건이 안 맞으면 참(예: ! -e file)

반복문(for, while, until)

반복문 작성시 아래 명령어(흐름제어)를 알아두면 좋다.

반복문 빠져나갈때: break

현재 반복문이나 조건을 건너뛸 때: continue

# 지정된 범위 안에서 반복문 필요시 좋다.
for string in "hello" "world" "..."; do;
    echo ${string};
done

# 수행 조건이 true일때, 실행됨(실행 횟수 지정이 필요하지 않은 반복문 필요시 좋다.)
count=0
while [ ${count} -le 5 ]; do
    echo ${count}
    count=$(( ${count}+1 ))
done

# 수행 조건이 false 일 때 실행됨.(실행 횟수 지정이 필요하지 않은 반복문 필요시 좋다.)
count2=10
until [ ${count2} -le 5 ]; do
     echo ${count2}
     count2=$((${count}+1))
done

조건문(if...elif...else...fi)

조건문 작성시 주의해야할 부분은 실행문장이 없으면 오류 발생한다.

string1="hello"
string2="world"
if [ ${string1} == ${string2} ]; then
  # 실행 문장이 없으면 오류 발생함.
  # 아래 echo 문장을 주석처리하면 확인 가능하다.
  echo "hello world"
elif [ ${string1} == ${string3} ]; then
  echo "hello world 2"
else
  echo "hello world 3"
fi

# AND
if [ ${string1} == ${string2} ] && [ ${string3} == ${string4} ]
..생략

# OR
if [ ${string1} == ${string2} ] || [ ${string3} == ${string4} ]
..생략

# 다중 조건
if [[ ${string1} == ${string2} || ${string3} == ${string4} ]] && [ ${string5} == ${string6} ]
..생략

선택문(case)

정규식을 지원하며 | 기호로 다중값을 입력 가능하며 조건의 문장 끝에는 ;; 기호로 끝을 표시한다.

참고로 대문자와 소문자는 다른 문자이다.

# case문 테스트를 위한 반복문
for string in "HELLO" "WORLD" "hello" "world" "s" "start" "end" "etc"; do
    # case 문 시작
    case ${string} in
        hello|HELLO)
            echo "${string}: hello     일때"
            ;;
        wo*)
                echo "${string}: wo로 시작하는 단어 일때"
                ;;
        s|start)
            echo  "${string}: s 혹은 staet 일때"
        e|end)
            echo  "${string}: e 혹은 end 일때"
            ;;
        *)
            echo "${string}: 기타"
            ;;
    esac
    # // case문 끝
done

디버깅(Debugging)

간단하게 echo, exit 명령이나 tee 명령어로 디버깅한다.
다른 방법으로 실행 시 옵션을 주거나 코드에 한줄만 추가하면 해볼 수 있다.

Bash 옵션 (스크립트 실행시) set 옵션 (스크립트 코드 삽입)  
bash -n set -n, set -o, noexec 스크립트 실행없이 단순 문법 오류만 검사
bash -v set -v 명령어 실행 전 해당 명령어 출력(echo)
bash -x set -x, set -o, xtrace 명령어 실행 후 해당 명령어 출력(echo)
  set -u, set -o, nounset 미선언된 변수 발견시 "unbound variable" 메시지 출력

Unix/Linux: Shebang 과 env에 대한 설명


심볼릭 링크(symbolic link)

- 링크를 연결하여 원본 파일을 직접 사용하는 것과 같은 효과를 내는 링크이다. 윈도우의 바로가기와 비슷한 개념

- 특정 폴더에 링크를 걸어 NAS, library 원본 파일을 사용하기 위해 심볼릭 링크를 사용한다.

ln -s [대상 원본 파일] [새로 만들 파일 이름]


반복문 for문 Loop 활용, 같이 쓰면 좋은 구문 break, continue

반복문 for 기본문법

for 변수 in [ 범위 ] (리스트 또는 배열 , 묶음 등 ) do 반복할 작업 done

for 변수 in [ 범위 ]( 리스트 또는 배열, 묶음 등 )
  do 
    반복할 작업
  done

In 뒤에 나오는 묶음의 개수만큼 반복이 진행된다.

in 뒤에 복수가 나오는데 쪼개질 수 있는 리스트나 배열, 명령어의 결과 묶음 등 다양한 것을 넣어 활용할 수 있다.
하나씩 순차적으로 빼서 변수에 저장하고 do ~ done 사이에 있는 작업을 진행한다.
어떤 디렉토리에 있는 파일을 하나하나 추출해서 do ~ done 사이에 있는 작업을 진행합니다.

다양한 반복문 문법과 활용법들

#!/bin/bash
for var in 1 2 3 4 5
do 
 echo var value :$var
done

in 리스트(list)

# case 1
list="1 2 3 4 5"
for var in $list
do
 echo var value :$var
done 

# case 2
for var2 in "1 2 3 4 5"
do 
 echo var2 value :$var2
done

Word Splitting

Shell은 변수의 값을 푶시할 떄 IFS(Internal Field Seperator) 변수에 설정된 값을 이용해 단어를 분리해 표시합니다. 여기서 단어를 분리한다는 의미는 IFS 변수에 설정된 문자를 space로 변경해 표시한다는 것입니다. 변수를 quote하게되면 단어 분리가 발생하지 않습니다.

$AA="11X22X33Y44Y55"

$ echo $AA
11X22X33Y44Y55

$IFS=XY
# IFS 값인 X,Y 문자가 space로 변경돼 표시된다.
$ echo $AA
11 22 33 44 55

# 변수를 quote 하게 되면 단어 분리가 발생하지 않는다.
$echo "$AA"
11X22X33Y55

# 따라서 IFS 변수 값을 출력하려면 quote를 해야합니다.
$ (IFS=@; echo $IFS )

$ (IFS=@; echo "$IFS" )
@
------
$(IFS=:;for v in $PATH; do echo "$v"; done)
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
...

IFS 기본값은 whitespace문자인 space, tab, newline 입니다. IFS변수가 unset됐을 때도 동일한 값이 적용되며, IFS 값이 null 이면 단어 분리가 일어나지 않습니다. read 명령으로 읽어들인 라인을 필드로 분리할 때, array 변수에 원소들을 분리해 입력할 때도 IFS 값이 사용됩니다.

$echo -n "$IFS"  | od -a

![image-20210627103931740](/Users/user/Library/Application Support/typora-user-images/image-20210627103931740.png)

echo -en "11 22\t33\n44"
echo 옵션 예제들
  • -n 옵션은 라인 끝에서 new line 을 제외시킵니다.
  • #!/bin/bash # -n 없이 출력시 echo "-n 옵션 미사용"
  • -e 옵션은 escape 문자(\n, \t, ' ') 등을 사용가능하게 한다.

참고 문헌

https://mug896.github.io/bash-shell/exp_and_sub/word_splitting.html
https://www.fun25.co.kr/blog/bash-echo-options-example/
https://blog.gaerae.com/2015/01/bash-hello-world.html
배열: http://blog.redjini.com/282

반응형

'' 카테고리의 다른 글

cask command not found  (0) 2021.07.02
mac 자바 버전 변경  (0) 2021.06.22
emacs  (0) 2021.06.22
hadoop  (0) 2021.06.07
tmux  (0) 2021.06.03
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함