정보
-
업무명 : 쉘 스크립트 사용법 (배열을 사용하는 법)
-
작성자 : 박진만
-
작성일 : 2020-07-18
-
설 명 :
-
수정이력 :
내용
[특징]
-
쉘 스크립트를 사용할 때의 유용한 팁 모음
[활용 자료]
-
없음
[자료 처리 방안 및 활용 분석 기법]
-
없음
[사용법]
-
작업 환경 구축
-
소스 코드 작성 및 실행
-
실행 결과 확인
[사용 OS]
-
Linux (CentOS v7.0)
- VMware Workstation Pro v15.5
[사용 언어]
-
Bash Script
소스 코드
[배열 사용법]
[배열에 값을 설정]
변수=(값1 값2 값3)
→ 값 목록에서 변수를 초기화한다.
-
괄호 안에 값의 목록을 제공 한 변수로 설정하여 그 변수를 배열로 사용할 수있다.
-
※ ksh의 경우 set 명령을 사용하여 배열 설정한다. 괄호를 사용하여 설정 방법은 사용하지 못할 수도 있으므로, ksh에서 배열을 사용하려면 set 명령을 사용한다.
$ array=(111 "foo" 222 "bar" 333 "foobar")
# ↑ 배열에 값을 설정한다.
$ echo $array
111
# ↑ 인덱스를 지정하지 않으면 첫 번째 값만 출력된다.
$ echo ${array[@]}
111 foo 222 bar 333 foobar
# ↑ 모든 값을 출력하는 경우 인덱스에 "@"를 지정한다.
-
ksh의 경우 다음과 같이 set 명령을 사용한다.
$ set -A array 111 "foo" 222 "bar" 333 "foobar"
↑ ksh의 경우 set 명령에 -A 옵션을 지정한 다음, 매개 변수 값 목록을 지정한다.
$ echo $array
111
$ echo ${array[@]}
111 foo 222 bar 333 foobar
-
괄호 안에 값을 직접 지정 이외에도 변수의 값이나 역 따옴표를 사용하여 명령의 실행 결과를 지정하는 것도 가능하다.
$ date
2020년 7월 17일 금요일 12:00:00 KST
$ array=(`date`)
$ echo ${array[3]}
금요일
# ↑ date 명령의 실행 결과를 배열로 변수 array로 설정되어있다.
$ VAR="hoge fuga foo bar"
$ array=($VAR)
$ echo ${array[3]}
bar
# ↑ 변수 VAR에 설정되어 있던 값이 배열로 변수 array로 설정되어있다.
[배열의 각 요소에 값을 설정]
배열 이름 [인덱스] = 값
→ 배열의 값을 개별적으로 설정하는 경우 인덱스를 지정할 필요가있다.
-
배열에 인덱스를 지정하는 것으로, 배열의 각 요소에 개별적으로 값을 설정할 수있다. 또한 괄호를 사용하여 배열에 설정 한 각 값은 선언 된 순서대로 배열 인덱스 0,1,2, ..., n에 저장된다.
-
즉, array=("foo" "bar")선언 된 경우 다음과 같이 설정 한 경우와 동일한 결과가된다.
-
array[0]="foo"
-
array[1]="bar"
-
-
인덱스로 지정 가능한 값은 숫자만으로 임의의 문자열을 지정할 수 없다 . 즉 연관 배열을 사용할 수 없다. 사용하여도 에러가되지 않지만, 의도한대로 움직이지는 않는다.
[배열에 요소를 추가]
[단일 요소를 추가]
배열이름+=(값)
→ 추가 할 값을 ()로 둘러싸고 배열 해지고 +=배열에 추가한다.
-
추가 할 요소를 ()이지 배열 화하면서 추가 대상 배열에 가산하여 요소를 추가 할 수 있다.
$ array=("hoge" "fuga" "foo" "bar")
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}"
hoge, fuga, foo, bar,
# ↑ 추가 대상 배열 (5 번째 요소가 없는 상태).
$ array+=("end")
# ↑ 5 번째 요소를 추가한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}"
hoge, fuga, foo, bar, end
# ↑ 5 번째 요소가 추가되어있다.
[여러 요소 추가]
배열이름+=(값 1 값 2 값 3)
→ 여러 값을 한 번에 추가하는 경우도 하나의 경우와 마찬가지로 ()이지 배열 화하면서 추가 할 요소를 공백으로 구분 나란히 가산한다.
$ array=("hoge" "fuga" "foo" "bar")
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
hoge, fuga, foo, bar, ,
# ↑ 추가 대상 배열 (5 번째, 6 번째 요소 없는 상태).
$ array+=("123" "456")
# ↑ 2 가지 요소를 한 번에 추가한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
hoge, fuga, foo, bar, 123, 456
# ↑ 5 번째, 6 번째의 요소가 추가되어있다.
-
2 개 이상의 요소를 한 번에 추가 할 경우에도 마찬가지로 ()으로 할 수 있다.
[변수의 값을 요소로 추가]
배열이름+=($변수이름)
→ 변수의 값을 배열의 요소로 추가한다.
-
문자열이나 숫자를 지정하는 것과 마찬가지로 변수의 값도 추가 가능하다. 변수의 값이 공백으로 구분 된 문자열 인 경우 여러 요소로 구성되는 경우가 있기 때문에 주의가 필요하다. 즉 하나의 요소로 배열에 추가하려면 변수를 ""로 둘러싸싸야 한다.
$ array=("hoge" "fuga" "foo" "bar")
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
hoge, fuga, foo, bar, ,
$ element="123 456"
# ↑ 요소로 추가 할 변수를 만들 수 있다.
$ array+=("$element")
# ↑ "" ""로 묶어 변수의 값을 하나의 요소로 추가한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
hoge, fuga, foo, bar, 123 456,
# ↑ 변수의 값이 5 번째 요소로 추가하고있다.
- 다음은 ""로 구분되지 않은 경우의 결과를 본다.
$ array=("hoge" "fuga" "foo" "bar")
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
hoge, fuga, foo, bar, ,
$ element="123 456"
$ array+=($element)
# ↑ "" ""로 묶여있지 않고 변수의 값을 추가한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
hoge, fuga, foo, bar, 123, 456
# ↑ 변수의 값이 5 번째와 6 번째 요소로 추가하고있다.
-
변수가 확장 된 상태 가 ""로 묶으면 array+=("123 456")이웃, ""로 구분되지 않은 경우 array+=(123 456)가되기 때문에 당연한 결과이지만 쉘 스크립트의 경험이 적은 사람은 간과이므로주의 할 것.
-
반대로 이것을 이용하여 공백으로 구분하여 설정된 변수 값을 여러 요소로 배열에 추가 할 수도 있다 .
-
미세한 차이로 결과가 크게 다르기 때문에 알기 힘든 사람도 있겠지만,이 배열의 경우에 한정하지 않고, 쉘 스크립트 변수 배포 한 후 최종적으로 어떤 형태로 명령이 실행되는지 를 이미지로 만들어 하는 것이 능숙의 지름길이다.
-
이번 같은 ""여부에 따른 동작의 차이에 대해서도 변수 확장 후 어떤 명령이 있는지를 이미지하면 바로 결과를 상상할 수 있을 것이다.
-
배열에 요소를 추가하는 방법은
- 추가 대상 배열의 모든 요소와 추가 할 값을 배열 화 다시 설정하는 방법 (eg array=("${array[@]}" "hoge"))과
- 현재의 요소 수에서 배열 끝의 인덱스를 구하고, 거기에 추가 할 요소를 설정하는 방법 (eg array[${#array[@]}]="hoge")
-
가 있지만, 이러한 방법이라고 추가 대상 배열의 인덱스가 불연속 인 경우에 문제가 발생할 .
-
추가 대상 배열의 모든 요소와 추가 할 값을 배열 화하고 재설정하는 방법으로 요소를 추가 해 본다.
$ array[0]="000"
$ array[2]="222"
$ array[5]="555"
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}, ${array[6]}"
000, , 222, , , 555,
# ↑ 인덱스가 불연속적인 배열을 생성한다.
$ array=("${array[@]}" "end")
# ↑ 모든 요소와 추가 할 값을 배열 화하여 설정한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}, ${array[6]}"
000, 222, 555, end, , ,
# ↑ 불연속이었던 인덱스가 얀속적인 것으로 변화하였다.
-
이 방법은 배열 요소의 추가가 아니라 엄밀하게는 배열의 재 작성 될 때문에 당연히 불연속이었다 인덱스 다시 작성되고 정상적으로 0에서 연속이다.
-
다음 현재 요소 수의 배열 끝의 인덱스를 구하고, 거기에 추가 할 요소를 설정하는 방법에 요소를 추가 해 본다.
$ array[0]="000"
$ array[2]="222"
$ array[5]="555"
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}, ${array[6]}"
000, , 222, , , 555,
# ↑ 인덱스가 불연속적인 배열을 생성한다.
$ array[${#array[@]}]="end"
# ↑ 요소 수를 인덱스로 지정하고 추가 할 요소를 설정한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}, ${array[6]}"
000, , 222, end, , 555,
# ↑ 배열의 끝이 아니라 세 번째 요소로 구성되어있다.
-
배열의 인덱스가 연속하고있는 경우는 배열의 "요소 수 = 말미 (마지막 요소의 다음) 인덱스 '가되지만, 인덱스가 불연속이면 당연히 이것은 성립되지 않는다.
-
위의 예에서도 요소가 세 개이기 위하여 array[3]="end"실행되어 인덱스가 3, 즉 네 번째 요소로 구성되어있다.
-
+= 를 사용하여 요소를 추가하여이 문제를 해결할 수 있다.
$ array[0]="000"; array[2]="222"; array[5]="555"
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}, ${array[6]}"
000, , 222, , , 555,
#↑# ↑ 인덱스가 불연속적인 배열을 생성한다.
$ array+=("end")
# ↑ "+ ="배열에 요소를 추가한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}, ${array[6]}"
000, , 222, , , 555, end
# ↑ 인덱스가 불연속인 경우에도 배열 끝에 추가되어있다.
-
배열에 요소를 추가하려면 '+ ='를 사용하는 것이 좋다.
-
또한 +=를 사용하는 경우, 추가 할 값을 ()이지 배열 화하는 것을 잊지 마십시오. 다음과 같이 ()으로 배열화하지 않고 추가하면 첫 번째 요소에 문자열로 추가되는만큼 추가되기 때문에 주의가 필요하다.
$ array=("hoge" "fuga" "foo" "bar")
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}"
hoge, fuga, foo, bar,
$ array+="end"
# ↑ 배열 화하지 않고 추가한다.
$ echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}"
hogeend, fuga, foo, bar,
# ↑ 선두의 요소 값의 끝에 추가되어있다.
[배열의 요소를 참조]
[각 요소 참조]
$ {배열이름[인덱스]}
→ 배열에 인덱스를 지정하면 각 요소의 값만을 참조 할 수있다.
-
배열의 참조 방법은 변수처럼 $를 사용하지만, 반드시 인덱스 부분을 포함한 변수 이름 전체 {}로 묶어야 한다.
$ date
2020년 7월 17일 금요일 12:25:04 KST
$ array=(`date`)
$ echo ${array[0]}
2020년
# ↑ 인덱스 부분을 포함하여 {}로 둘러싼 다.
$ index=3
$ echo ${array[$index]}
금요일
# ↑ 인덱스는 변수를 지정할 수도 있다.
$ echo $array
2020년
# ↑ 인덱스를 지정하지 않으면 첫 번째 값이 참조된다.
$ echo $array[3]
2020년[3]
# ↑ 인덱스를 지정하는 경우 {}를 생략하면 제대로 볼 수 없다.
[모든 요소 참조]
-
배열에 설정되어있는 모든 값을 한 번에 볼 수 있다.
${배열이름[@]}
→ 인덱스 @를 지정하여 배열의 모든 값이 공백으로 구분하여 출력된다.
- 덧붙여서 @이외에도 *이 가능하다. 이 둘의 차이는 앞서 언급되어있는 $@과 $*의 차이와 같다.
$ array=("foo" "bar" "hoge" "fuga" "HOGE HOGE" "FUGA FUGA")
$ echo ${array[@]}
foo bar hoge fuga HOGE HOGE FUGA FUGA
# ↑ 인덱스에 "@"를 지정했기 때문에 배열의 모든 요소 값이 공백으로 구분하여 출력되고있다.
$ for i in "${array[@]}"
> do
> echo $i
> done
foo
bar
hoge
fuga
HOGE HOGE
FUGA FUGA
$ for i in "${array[*]}"
> do
> echo $i
> done
foo bar hoge fuga HOGE HOGE FUGA FUGA
-
인덱스 @를 사용하여 배열의 참조는 for 문을 사용하는 경우에 매우 편리하다. 다음은 그 예 (atmark.sh).
#!/bin/bash
# 현재 디렉토리의 파일 이름 목록을 배열에 저장
files=(`ls -1`)
# 인덱스에 @를 지정하여 모든 요소를 for 문에 값 목록에 지정
for file in ${files[@]}
do
# 각 파일의 파일 크기
size=`ls -l $file | awk '{print $5}'`
echo "FILE: $file - $size byte"
done
exit 0
-
이 쉘 스크립트 atmark.sh의 실행 결과는 다음과 같다
$ ./atmark.sh
FILE: atmark.sh - 372 byte
FILE: file1 - 165 byte
FILE: file2 - 531 byte
FILE: file3 - 655 byte
FILE: file4 - 1454 byte
FILE: file5 - 541 byte
-
각 요소에 대한 처리를 할 경우에는 for 문 목록에 인덱스에 '@'를 지정한 배열을 지정하면 foreach 문 같은 처리를 쉽게 설명 할 수있다.
[배열의 요소를 참조2]
$ {#배열이름[*]}
→ 배열 이름 앞에 #으로 전체 배열 (인덱스로 *지정)를 참조한다.
-
변수 이름 #을 부가 한 참조는 변수의 설정 값의 문자에 열기 있지만, 배열 이름 (정확하게는 배열 이름 [*])에 #를 추가하여 참조하면 배열의 전체 요소 수에 전개된다.
$ array=("foo" "bar" "hoge" "fuga" "HOGE HOGE" "FUGA FUGA")
$ echo "${#array[*]}"
6
$ echo "${#array[@]}"
6
# ↑ 인덱스에 "@"를 지정하여도 결과는 같다.
[배열의 요소 반복]
for i in "${array[@]}"
do
...
done
→ for 문장에 큰 따옴표로 묶 인덱스 @를 지정하는 배열을 전달한다.
-
배열의 모든 요소에 대해 작업을 수행하려는 경우에 배열의 요소에서 루프를 실시하고 싶은 경우는 for 문 루프 대상으로 큰 따옴표로 묶 인덱스 @를 지정하는 배열을 전달합니다.
-
주의 할 점은 두 가지.
- 요소에 공백이 포함 된 것을 고려하고 큰 따옴표로 묶기
- *대신 @을 사용 해야 함
-
요소에 공백이 들어 있지 않은 것을 보증 할 수 있다면 큰 따옴표를 사용할 필요없이 *와 @의 구별도 필요하지 않지만, 모범 사례로 배열 루프 처리를 할 경우 큰 따옴표와 @를 사용하면 기억하기 원한다 .
-
덧붙여서, 더블 쿼트와 *를 사용하면 쉘이 배열 전체를 하나의 값으로 전개하기 때문에 요소가 몇개 있으려고도 루프가 한 번에 종료 해 버린다.
$ # 「*」を使用してしまったダメな例
$ array=(1 2 3 4 5)
$ for i in "${array[*]}"
> do
> echo "[${i}]"
> done
[1 2 3 4 5]
# ↑ 요소가 5 개 있지만, 루프가 한번에 종료되어었음.
$ # "@"를 사용한 올바른 예
$ array=(1 2 3 4 5)
$ for i in "${array[@]}"
> do
> echo "[${i}]"
> done
[1]
[2]
[3]
[4]
[5]
# ↑ 각 요소의 루프가 실행된다.
-
인덱스 @를 지정하는 것으로, 쉘 for i in "1" "2" "3" "4" "5"해석하고 요소 몇분의 루프 처리를 할 수있다.
-
또한 큰 따옴표를 사용하지 않으면 *및 @중 어느 것을 사용해도 결과는 동일하지만 다음과 같은 요소에 공백이있는 경우에 문제가 발생한다.
# 배열의 요소가 공간을 포함하는 경우 (큰 따옴표를 사용하지 않음)
$ array=(1 2 3 4 5 "6 6")
$ for i in ${array[*]}
> do
> echo "[${i}]"
> done
[1]
[2]
[3]
[4]
[5]
[6]
[6]
# ↑ "6 6"이 큰 따옴표가 없기 때문에 2 개의 요소로 해석되기 때문에 반복 횟수가 1 회 많아지고있다.
$ for i in ${array[@]}
> do
> echo "[${i}]"
> done
[1]
[2]
[3]
[4]
[5]
[6]
[6]
# ↑ "6 6"이 큰 따옴표가 없기 때문에 2 개의 요소로 해석되기 때문에 반복 횟수가 1 회 많아지고있다.
-
큰 따옴표를 사용하지 않으면 쉘 for i in 1 2 3 4 5 6 6해석한다. 따라서 요소 "6 6"을 2 개의 요소로 간주되어 버린다.
-
이러한 문제를 피하기 위해 반복되는데, 모범 사례로 배열 루프 처리를 할 경우 큰 따옴표와 @를 사용하는 것.
$ array=(1 2 3 4 5 "6 6")
$ for i in "${array[@]}"
> do
> echo "[${i}]"
> done
[1]
[2]
[3]
[4]
[5]
[6 6]
# ↑ 큰 따옴표와 '@'을 사용하여 공간을 포함한 요소에도 대응 가능.
[배열의 요소를 정렬]
-
문자열로 정렬
_IFS="$IFS"; IFS="\n"; array=(`for item in "${array[@]}"; do echo "$item"; done | sort`); IFS="$_IFS"
→ 배열의 모든 요소를 출력 한 후 sort 명령에서 정렬을 실행하고 실행 결과를 다시 배열에 저장한다.
-
배열의 요소에 공백이 포함 된 경우를 고려하여 사전에 IFS줄 바꿈 만 변경하여 둔다. 이렇게두면 정렬 결과의 배열에 재구성하는 동안 공백으로 구분 요소가 설정되는 것을 방지한다. 변경된 IFS마지막으로 취소합니다.
-
배열은 for 문에 "${array[@]}"처럼 모든 요소를 의미하는 @사용 큰 따옴표로 묶인에 지정한다. 이 지정은 각 요소가 큰 따옴표로 둘러싸인 상태로 배열이 전개된다.
-
즉, for 문에서 사용되는 변수 item에 배열 (요소의 공백 구분 단위가 아닌) 각 요소 단위로 값이 대입된다.
-
또한 각 요소별로 echo를 출력함으로써 모든 요소가 줄 바꿈으로 구분하여 출력되므로 sort 명령으로 정렬이 가능하게된다.
-
정렬 된 모든 요소를 줄 바꿈으로 구분하여 다시 배열로 설정하면 배열의 모든 요소를 정렬 할 수있게된다. 배열에 다시 설정 될 때 IFS이 줄 바꿈 만되어 있지 않은 경우, 줄 바꿈과 공백으로 구분하여 배열에 다시 설정되는 것이기 때문에 사전에 IFS줄 바꿈 만 변경하는 것이 필요하지만있다. 먼저 IFS변경하고있는 것은 그 때문이다.
$ array=("222 222" "ccc ccc" "aaa aaa" "111 111" "bbb bbb" "333 333")
# ↑ 테스트의 배열을 생성한다.
$ for item in "${array[@]}"
> do
> echo $item
> done
222 222
ccc ccc
aaa aaa
111 111
bbb bbb
333 333
# ↑ 모든 요소는 상기와 같이 (줄 바꿈으로 구분하여 출력).
_IFS="$IFS";IFS="\n";array=(`for item in "${array[@]}"; do echo "$item"; done | sort`);IFS="$_IFS"
# ↑ 사전 IFS를 줄 만 변경하고 정렬 된 출력을 배열에 다시 설정한다.
$ for item in "${array[@]}"; do echo "$item"; done
111 111
222 222
333 333
aaa aaa
bbb bbb
ccc ccc
# ↑ 실행 후 배열은 정렬 된 값이 설정되어있다.
-
숫자로 정렬
-
요소를 문자열이 아닌 숫자로 정렬하려면 sort 명령에 -n옵션을 지정한다.
array=(`for item in "${array[@]}"; do echo "$item"; done | sort -n`)
→ -n옵션을 지정하고 숫자로 정렬 한 후 배열에 저장한다.
-
배열의 요소가 수치 뿐이다 경우에는 공백을 포함하는 것을 상정하지 않으므로 IFS를 변경할 필요가 없다.
$ array=(2 3 04 000 001)
$ for item in "${array[@]}"; do echo "$item"; done
2
3
04
000
001
$ for item in "${array[@]}"; do echo "$item"; done | sort
000
001
04
2
3
$ for item in "${array[@]}"; do echo "$item"; done | sort -n
000
001
2
3
04
$ array=(`for item in "${array[@]}"; do echo "$item"; done | sort -n`)
$ for item in "${array[@]}"; do echo "$item"; done
000
001
2
3
04
참고 문헌
[논문]
- 없음
[보고서]
- 없음
[URL]
- 없음
문의사항
[기상학/프로그래밍 언어]
- sangho.lee.1990@gmail.com
[해양학/천문학/빅데이터]
- saimang0804@gmail.com
본 블로그는 파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음
'프로그래밍 언어 > Shell Script' 카테고리의 다른 글
[ShellScript] 쉘 스크립트 날짜 기간에 대한 파일 조회 및 일별 통계 생산 (0) | 2021.01.06 |
---|---|
[ShellScript] 쉘 스크립트 UTC 시간에 대한 파일을 이용한 KST 시간 변환 (0) | 2021.01.03 |
[ShellScript] 쉘 스크립트 사용법 (변수를 사용하는 법) (2) | 2020.07.17 |
[ShellScript] 쉘 스크립트를 사용할 때 코드 작성 팁 (2) | 2020.07.17 |
[Shell Script] 쉘 스크립트 (bash) 개발자가 빠지기 쉬운 함정 (3) (0) | 2020.03.23 |
최근댓글