[Linux] 쉘 스크립트에서 멀티프로세스(혹은 스레드) 기능 사용하기
백그라운드로 명령어를 실행해서 병렬적으로 실행되는 멀티 프로세스 환경을 만들어보자.
환경
- Linux 기반 시스템
- Bash shell(/bin/bash)
멀티프로세스? 병렬처리? 멀티스레드? 백그라운드 프로세스?
- 여기서 진행할 방식은
&
연산자를 이용해 명령어나 쉘스크립트의 내용을 백그라운드로 실행시키는 방식을 사용할 예정입니다. - 여기저기 찾아본 결과
&
연산자를 이용하면 해당 명령어나 스크립트는 현재 실행되는 프로세스의 자식 프로세스를 생성하여 새로운 서브쉘에서 실행된다고 합니다. - 정확하게 명칭을 멀티프로세스나 멀티스레드라고 부르기 애매하나… 영문 자료들에서
&
연산자를 이용해 자식 프로세스를 만든다고 하여 멀티프로세스라고 이름 지었습니다. 혹시 다른 내용이나 더 정확한 내용을 알고 계시면 자료 첨부와 함께 댓글 달아주시면 감사하겠습니다 :)
리눅스 &(Ampersand) 연산자
& 연산자란?
- 리눅스 환경에서 명령어를 실행할 때 현재 사용하고 있는 쉘이 아닌 새로운 서브쉘을 생성해서 백그라운드에서 실행할 때 사용하는 명령어입니다.
&
를 사용해서 명령어나 스크립트를 실행하면 백그라운드로 해당 명령어나 스크립트가 실행되며 쉘에서 다른 작업을 계속 할 수 있습니다.- 다음 아래 예제들처럼 원하는 명령어를 다 입력한 후에
&
를 붙여주면 됩니다.
& 연산자 예제
- (예제)
sleep
을 백그라운드에서 실행하기
$ sleep 10 &
[1] 79287
$ # Type enter to make below result
[1]+ Done sleep 10
- (예제) shell script를 백그라운드에서 실행하기
- 다음 아래처럼
명령어 > 파일명 &
방식을 이용해stdout
을 로그파일로 남길수도 있습니다.
$ tee test_shell.sh << EOF
> #!/bin/bash
>
> echo 1
> sleep 1
> echo 2
> sleep 1
> echo 3
> EOF
echo 1
sleep 1
echo 2
sleep 1
echo 3
$ ./test_shell.sh > tmp_test_shell.log & # You can redirect stdout to specific file.
(예제) 쉘스크립트 함수를 백그라운드에서 병렬로 사용하기
설명
- 함수를 만들고 해당 함수에 인자를 전달해서 백그라운드로 돌리는 예제를 작성해보겠습니다.
- 아래 예제는 배열에 있는 원소들을 인자로 전달하여 랜덤한 값에 따라 sleep을 하는 스크립트입니다.
&
를 사용하지 않는다면 각각 배열의 원소에 대하여 랜덤한 시간만큼 sleep이 끝날 때까지 순차적으로 기다리겠지만&
를 사용했기 때문에 각각의 작업은 백그라운드에서 따로 진행됩니다. - 각각 자식 프로세스들이 잘 생성되고 실행되었는지를 확인하기 위해 배열 원소의 이름으로 로그 파일을 만들었습니다.
코드
test_multi_process.sh
#!/bin/bash
function back_ground_process () {
# Random number between 10 and 15
sleep_time=$(($RANDOM*12345%6 + 10))
echo "${1} will sleep for ${sleep_time} seconds"
sleep ${sleep_time}
echo "${1} sleep done!"
}
# array in shell script
arr=("a_worker" "b_worker" "c_worker")
# @ means all elements in array
for i in ${arr[@]}; do
# run back_ground_process function in background
# pass element of array as argument
# make log file
back_ground_process $i > ~/log_${i}.txt &
done
wait
라는 명령어를 사용하면 현재 실행된 스크립트에서 생성된 모든 자식 프로세스 및 백그라운드 작업을 기다릴수 있습니다.
test_multi_process.sh(continue)
...
# @ means all elements in array
for i in ${arr[@]}; do
# run back_ground_process function in background
# pass element of array as argument
# make log file
back_ground_process $i > ~/log_${i}.txt &
done
# wait until all child processes are done
wait
echo "All background processes are done!"
결과
- 실행하고 바로 로그 파일들을 확인합니다.
- 쉘 스크립트는 백그라운드로 작업을 각각 돌리고 바로 종료되는걸 볼 수 있습니다.
$ ./test_multi_process.sh
$ cat log_a_worker.txt && cat log_b_worker.txt && cat log_c_worker.txt
a_worker will sleep for 13 seconds
b_worker will sleep for 13 seconds
c_worker will sleep for 10 seconds
- 15초 정도가 지난후에 로그파일들을 보면 각각의 프로세스가 끝났음을 알 수 있습니다.
$ cat log_a_worker.txt && cat log_b_worker.txt && cat log_c_worker.txt
a_worker will sleep for 13 seconds
a_worker sleep done!
b_worker will sleep for 13 seconds
b_worker sleep done!
c_worker will sleep for 10 seconds
c_worker sleep done!
응용
- 위와 같이
&
를 사용해서 사용하고 싶은 데몬이나 프로세스들을 백그라운드로 실행할 수 있습니다. - 예를 들어서 여러개의 컴퓨터에 동시에 접속해서 어떤 파일을 설치하는 명령어들을 백그라운드로 병렬로 실행해서 시간을 단축시킬 수 있으며 현재 쉘에서 특정 프로그램을 실행 시키고 계속 현재 쉘을 사용하고 싶을 때 유용합니다.
- 추가적으로 쉘 스크립트에서 백그라운드로 멀티 프로세스를 진행시키고 싶을 때 사용이 가능합니다.
참고자료
- https://stackoverflow.com/questions/3004811/how-do-you-run-multiple-programs-in-parallel-from-a-bash-script/3004814
- https://wiki.kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/x5472.html
- https://unix.stackexchange.com/questions/86247/what-does-ampersand-mean-at-the-end-of-a-shell-script-line
- https://bashitout.com/2013/05/18/Ampersands-on-the-command-line.html