-
[Bash] 스크립트 제어Programming/Shell 2017. 12. 11. 01:32
신호 처리
리눅스는 시스템에서 실행되는 프로세스와 통신하기 위해 신호를 사용한다. 스크립트가 특정한 신호를 수신했을 때 특정한 명령을 수행하기 위해 스크립트를 프로그래밍 함으로써 쉘 스크립트의 동작을 제어할 수 있다.
Bash 쉘에게 전달되는 신호
- 시스템 및 어플리케이션 이 만들 수 있는 30개가 넘는 리눅스 신호가 있다.
신호
값
설명
1
SIGHUP
프로세스를 끊는다.
2
SIGINT
프로세스를 중지시킨다.
3
SIGOUIT
프로세스를 중단시킨다.
9
SIGKILL
무조건 프로세스를 종료한다.
15
SIGTERM
가능하면 프로세스를 종료한다.
17
SIGSTOP
무조건 프로세스를 중단하지만 종료하지는 않는다.
18
SIGTSTP
프로세스를 중단 또는 일시 중지하지만 종료하지는 않는다.
19
SIGCONT
중단되었던 프로세스를 계속한다.
- 기본적으로 bash 쉘은 3 및 15 신호를 받았을 때에는 이를 무시한다. 그러나 bash 쉘은 1 및 2 신호를 받았을 때에는 이를 무시하지 않는다.
- 대화형 쉘은 떠날 때와 같은 시기에 bash 쉘이 SIGHUP 신호를 받으면 쉘은 종료된다. 하지만 종료 직전에 실행 중인 쉘 스크립트를 포함해서 쉘에서 실행된 모든 프로세스에 SIGHUP 신호를 전달한다.
- 2 신호를 받으면 쉘은 잠시 중단된다. 리눅스 커널은 CPU에 쉘을 처리하는 시간을 주는 일을 멈추고, 이 상황을 쉘에서 시작된 모든 프로세스에 알리기 위해 이들 프로세스에 SIGINT 신호를 전달한다.
- 쉘 스크립트의 기본 동작은 이러한 신호를 통제하지 않으므로 스크립트의 동작에 악영향을 미칠 수 있다. 이러한 상황을 막기 위해 스크립트가 신호를 인식하고 스크립트가 신호의 결과에 대한 준비를 하기 위해 명령을 수행하도록 만들 수 있다.
신호 만들기
- Bash 쉘은 키보드의 키 조합을 사용하여 두 가지 기본 리눅스 신호를 만들 수 있다. (스크립트 중단 or 일시 중단 시에 편리)
프로세스 중지시키기
- <Ctrl> + <C> 키 조합은 SIGINT 신호를 만들어내고 이를 현재 쉘에서 실행되는 프로세스로 보낸다. 보통 시간이 오래 걸리는 명령을 실행하고 <Ctrl>+<C> 키 조합을 눌러 이를 테스트할 수 있다.
[root@centos ~]# sleep 100
╚
- <Ctrl> + <C> 키 조합은 쉘에서 현재 실행 중인 프로세스를 중단시키는 SIGINT 신호를 전송한다. Sleep 명령은 지정된 시간(초) 동안 쉘의작업을 일시 중지시킨 다음 쉘 프롬프트로 돌아간다.
프로세스 일시 중지시키기
- 프로세스를 종료하는 대신 도중에 일시 정지시킬 수도 있다. <Ctrl>+<Z> 키 조합은 SIGTSTP 신호를 보내서 쉘에서 실행 중인 모든 프로세스를 중지시킨다. 프로세스 중지시키는 것은 종료하는 것과는 다르다. 프로세스를 중지시키면 프로그램을 메모리에 남겨두며 중단되었던 곳에서부터 동작을 재개시킬 수 있다.
[root@centos ~]# sleep 100
[1]+ Stopped sleep 100
[root@centos ~]# exit
logout
There are stopped jobs.
- 대괄호 안의 숫자는 쉘이 할당한 작업 번호다. 쉘은 실행되는 각 프로세스를 작업(job)으로 보고 고유한 작업 번호를 지정한다.(현재 쉘)
- 쉘 세션 안에서 할당된 작업을 중단시키면 쉘을 종료하려고 할 때 bash는 경고 메시지를 보낸다.
[root@centos ~]# ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 3685 3142 0 80 0 - 49411 poll_s pts/0 00:00:00 sudo
4 S 0 3686 3685 0 80 0 - 47437 do_wai pts/0 00:00:00 su
4 S 0 3687 3686 0 80 0 - 28848 do_wai pts/0 00:00:00 bash
0 T 0 3704 3687 0 80 0 - 26976 do_sig pts/0 00:00:00 sleep
- 중단된 작업을 T로 표시한다. 이는 추적되고 있거나 중단되었음을 뜻한다. 중단된 작업이 아직 살아 있는데도 쉘을 종료하려고 하면 다시 exit 명령을 입력하면 된다.
신호 트랩
- 스크립트 신호를 신경 쓰지 않도록 내버려두는 대신 신호가 나타나고 다른 명령을 수행할 때 신호를 가로챌(트랩) 수 있다. Trap 명령은 리눅스 쉘 스크립트가 어떤 신호를 볼 수 있고 트랩할 수 있는지를 지정한다.
trap Commands signals
- 트랩 커맨드라인에서 쉘을 실행시키려는 명령들을 나열하고 그 다음 트랩하고자 하는 신호들을 빈 칸으로 구분해서 나열한다. (숫자 or 이름)
- SIGINT 신호를 트랩해서 신호가 전송될 때 스크립트의 동작을 제어하는 trap 명령을 사용하는 예
#!/bin/bash
# Tseting signal trapping
trap "echo ' Sorry!! I have trapped Ctrl=C'" SIGINT
echo This is a test script
#
count=1
while [ $count -le 10 ]
do
echo "Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
#
echo "This is the end of the test script"
#
- Trap 명령어는 SIGINT 신호를 검출할 때마다 간단한 텍스트 메시지를 표시한다. 신호를 트랩하면 이 스크립트가 Bash 쉘 키보드 <Ctrl>+<C>명령을 사용하여 프로그램을 중지하려고 시도하는 사용자에게 영향을 받지 않도록 만들 수 있다.
[root@centos ~]# ./test.sh
This is a test script
Loop #1
Loop #2
Loop #3
Loop #4
Loop #5
Loop #6
Loop #7
╚ Sorry!! I have trapped Ctrl=C
Loop #8
Loop #9
╚ Sorry!! I have trapped Ctrl=C
Loop #10
This is the end of the test script
스크립트 종료 트랩하기
- 쉘 스크립트에서 신호를 포착하는 것 말고도 쉘 스크립트가 종료될 때에도 트랩을 쓸 수 있다. 이는 쉘 작업을 완료하려고 할 때 명령을 실행할 수 있는 편리한 방법이다.
trap "echo Goobye..." EXIT
#
count=1
while [ $count -le 10 ]
do
echo "Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
- 스크립트가 정상 종료 지점에 이르렀을 때 트랩이 작동되고 쉘은 trap 명령에서 지정한 명령을 실행한다. EXIT 트랩은 일찍 스크립트를 종료할 때에도 작동 된다.
[root@centos ~]# ./test.sh
Loop #1
Loop #2
Loop #3
Loop #4
Loop #5
Loop #6
Loop #7
Loop #8
Loop #9
Loop #10
Goobye...
[root@centos ~]# ./test.sh
Loop #1
Loop #2
╚Goobye...
- SIGINT 신호가 trap 신호 목록에 포함되어 있지 않으므로 이 신호를 전송하기 위해 <Ctrl>+<C>키 조합을 썻을 때 스크립트는 종료된다.
Trap 수정 또는 제거
- 쉘 스크립트의 다양한 부분에서 트랩을 다양하게 처리하려면 trap 명령을 새로운 옵션으로 다시 쓰면 된다.
#
trap "echo ' Sorry!! Ctrl-C is trapped.'" SIGINT
count=1
while [ $count -le 5 ]
do
echo "Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
#
trap "echo ' I modified the trap!'" SIGINT
count=1
while [ $count -le 5 ]
do
echo "Second Loop #$count"
sleep 10
count=$[ $count + 1 ]
done
- 신호 트랩이 수정된 후, 스크립트는 해당 신호를 다르게 처리한다. 트랩이 수정되기 전에 신호가 수신된 경우에는 스크립트 원래 trap 명령에 따라서 처리한다.
[root@centos ~]# ./test.sh
Loop #1
Loop #2
╚ Sorry!! Ctrl-C is trapped.
Loop #3
Loop #4
Loop #5
Second Loop #1
Second Loop #2
╚ I modified the trap!
Second Loop #3
╚ I modified the trap!
Second Loop #4
- 일련을 제거할 수도 있다. Trap 명령 뒤에 두 개의 대시를 사용하고 기본 동작으로 돌아갈 신호의 목록을 쓰면 된다.
# test3d.sh
trap "echo ' Sorry!! Ctrl-C is trapped.'" SIGINT
count=1
while [ $count -le 5 ]
do
echo "Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
trap -- SIGINT
echo "I just removed the trap"
count=1
while [ $count -le 5 ]
do
echo "Second Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
- 신호 처리를 기본 동작으로 돌려놓기 위해 이중 대시 대신 단일 대시를 사용할 수도 있다.
[root@centos ~]# ./test.sh
Loop #1
╚ Sorry!! Ctrl-C is trapped.
Loop #2
Loop #3
Loop #4
Loop #5
I just removed the trap
Second Loop #1
Second Loop #2
╚
백그라운드 모드에서 스크립트 실행하기
수 많은 프로세스가 있는데, 지금 터미널에서 실행시키고 있지 않은 프로세스는 백그라운드에서 실행 중인 프로세스라고 한다.
스크립트를 처리하는데 시간이 오래 걸리거나 커맨드라인 인터페이스가 이를 기다리느라 묶여 있지 않는 편이 좋을 수 있다. 스크립트가 실행되는 동안은 터미널 세션에서 다른 작업을 수행할 수 없다. 이러한 문제 해결할 간단한 해결책이 있다.
백그라운드에서 실행하기
-백그라운드 모드에서 쉘스크립트를 실행하려면 커맨드라인 인터페이스에서 명령 다음 앰퍼샌드(&) 기호를 놓기만 하면 된다.
$ cat test.sh
#!/bin/bash
# Test running in the background
#
count=1
while [ $count -le 10 ]
do
sleep 1
count=$[ $count + 1 ]
done
#
- 앰퍼샌드 기호를 두면 이 명령으 bash 쉘로부터 분리되어 시스템에서 별도의 백그라운드 프로세스로 실행된다.
[1] 4246
- 괄호 안의 숫자는 쉘이 백그라운드 프로세스에 할당하 작업 번호이고, 다음 숫자는 리눅스 시스템이 프로세스에 할당하는 프로세스 ID다.
- 이 작업을 시작할 때 사용된 명령과 함께 작업 번호 및 작업의 상태(Done)가 표시된다.
[1] Done ./test.sh
- 백그라운드 프로세스가 실행되는 동안 STDOUT 및 STDERR 메시지는 계속해서 터미널 모니터를 사용한다는 점에 유의하자.
[root@master /]# cat test.sh
#!/bin/bash
echo "Start the test script"
count=1
while [ $count -le 5 ]
do
echo ""Loop #$count"
sleep 5
count=$[ $count +1 ]
done
echo "Test script is complete"
[root@master /]# ./test.sh &
[1] 4527
[root@master /]# Start the test script
Loop
Loop
Loop
Loop
Loop
Test script is complete
[1]+ Done ./test.sh
- Tet.sh 스크립트가 백그라운드에서 실행되는 동안 다른 명령을 입력할 수 있다. 스크립트 출력, 입력된 명령, 명령의 출력이 모두 출력 표시에서 뒤섞이기 때문에, 백그라운드에서 실행시킬 목적으로 만든 스크립트에서는 STDOUT 및 STDERR을 리다이렉트 하는 것이 좋다.
여러 백그라운드 작업 실행하기
- 커맨드라인 프롬프트에서 동시에 몇 개든 백그라운드 작업을 실행시킬 수 있다.
[root@master /]# ./test.sh &
[1] 4599
[root@master /]# Start the test script
Loop
[root@master /]#
[root@master /]# ./test.sh &
[2] 4601
[root@master /]# Start the test script
Loop
[root@master /]#
[root@master /]# ./test.sh &
[3] 4603
[root@master /]# Start the test script
Loop
- 새로운 작업을 시작할 때마다 리눅스 시스템은 새 작업 번호와 PID를 할당한다. Ps 명령으로 실행되고 있는 모든 스크립트를 볼 수 있다.
[root@master /]# ps
PID TTY TIME CMD
4211 pts/0 00:00:00 sudo
4212 pts/0 00:00:00 su
4213 pts/0 00:00:00 bash
4599 pts/0 00:00:00 test.sh
4601 pts/0 00:00:00 test.sh
4603 pts/0 00:00:00 test.sh
- 터미널 세션에서 백그라운드 프로세스를 사용할 때에는 주의해야 한다. Ps 명령의 출력을 보면 각 백그라운드 프로세스는 터미널 세션(pts/0)에 연결되어 있는데, 이 터미널 세션이 종료되면 백그라운드 프로세스 역시 종료된다.
끊임 없이 스크립트 실행하기
- 터미널 세션을 종료 뒤에도 백그라운드 모드에서 실행되는 스크립트의 작업이 완료될 떄까지 실행시켜야 할 수 있다. nohup 명령은 프로세스로 전송되는 모든 SIGHUP 신호를 차단하는 다른 명령을 실행한다. 이 명령을 사용하면 터미널 세션을 종료할 때 프로세스가 함께 종료되는 것을 막을 수 있다.
- 정상적인 백그라운드 프로세스와 마찬가지로 쉘은 명령을 작업 번호를 할당하고 PID번호를 할당한다. 차이점은 nohup 명령을 사용하면 쉘 세션을 닫았을 때 스크립트가 터미널이 전송한 SIGHUP 신호를 무시한다는 것이다.
- nohup 명령은 프로세스와 터미널의 관계를 끊기 때문에 프로세스는 STDOUT 및 STDERR 출력 링크는 잃는다. 명령이 만들어내는 출력을 수용하기 위해 nohup 명령은 STDOUP 및 STDERR 메시지를 자동으로 nohup.out 파일로 리다이렉트한다.
[root@master /]# nohup ./test.sh &
[1] 4620
[root@master /]# nohup: ignoring input and appending output to ânohup.outâ
[root@master /]# cat nohup.out
Start the test script
Loop
Loop
Loop
작업제어
- 작업을 시작,중단,종료,재개시키는 기능을 작업 제어라고 한다. 작업 제어 기능으로 쉘 환경에서 프로세스가 실행되는 방법을 완벽하게 제어할 수 있다.
작업보기
- 작업 제어의 핵심은 작업 jobs 명령이다. Jobs 명령은 쉘이 처리하고 있는 현재의 작업을 볼 수 있다.
- 이 스크립트는 리눅스 시스템이 스크립트에 할당한 PID를 표시하기 위해 $$ 변수를 사용한다. 그 다음 루프문으로 들어가서 한번 되풀이 될 때마다 10초씩 멈춘다.
[root@master /]# cat test10.sh
#!/bin/bash
# Test job control
echo "Script Process ID: $$"
count=1
while [ $count -le 10 ]
do
echo "Loop #$count"
sleep 10
count=$[ $count + 1 ]
done
echo "End of Script..."
- 스크립트를 시작한 후 <Ctrl> + <Z> 키 조합을 사용하여 이 스크립트를 중단시킬 수 있다.
[root@master /]# ./test10.sh
Script Process ID: 4653
Loop #1
Loop #2
^Z
[1]+ Stopped ./test10.sh
- 앰퍼샌드 기호로 같은 스크립트를 이용한 다른 작업이 백그라운드 프로세스로 실행된다. 일을 좀 더 쉽게 하기 위해 스크립트의 출력을 파일로 리다이렉트해서 출력이 화면에 나타나지 않도록 한다.
[root@master /]# ./test10.sh > test10.out &
[2] 4656
- Jobs 명령은 쉘에서 할당한 작업을 볼 수 있다. 중단된 작업과 실행 중인 작업을 모두 보여주며, 작업 번호 및 작업에 사용된 명령이 함께 표시된다.
- Jobs 명령에 -l 매개변수를 추가하여 여러 작업들의 PID를 볼 수 있다.
- 플러스 기호 작업은 기본 작업으로 간주된다. 어떤 작업 제어 명령이든 작업 번호를 커맨드라인에 지정하지 않는다면 기본 작업이 제어 명령의 영향을 받는다.
- 마이너스 기호가 붙은 작업은 현재 기본 작업이 완료했을 때 기본 작업이 될 작업이다. 플러스 기호는 항상 하나의 작업에만 붙으며 마이너스 기호도 한 작업에만 붙는다.
[root@master /]# jobs
[1]+ Stopped ./test10.sh
[2]- Running ./test10.sh > test10.out &
[root@master /]# jobs -l
[1]+ 4653 Stopped ./test10.sh
[2]- 4656 Running ./test10.sh > test10.out &
- 기본 작업이 제거되었을 때 그 다음 작업이 어떻게 그 자리를 넘겨받는지 보여주는 예이다.
[root@master /]# ./test10.sh > test10.out &
[1] 4727
[root@master /]# ./test10.sh > test10.out &
[2] 4729
[root@master /]# ./test10.sh > test10.out &
[3] 4731
[root@master /]# ./test10.sh > test10.out &
[4] 4734
[root@master /]# jobs -l
[1] 4672 Running ./test10.sh > test10.out &
[2] 4674 Running ./test10.sh > test10.out &
[3] 4676 Running ./test10.sh > test10.out &
[4]- 4678 Running ./test10.sh > test10.out &
[5]+ 4680 Running ./test10.sh > test10.out &
- 기본 프로세스에 SIGHUP 신호를 보내 kill 명령을 사용하면 작업이 종료된다. 그 다음에 jobs 목록을 보면 이전에 마이너스 기호의 작업이 이제 더하기 기호로 가지고 있으며 기본 작업이 되었다.
[root@master /]# jobs -l
[1] 4772 Running ./test10.sh > test10.out &
[2]- 4774 Running ./test10.sh > test10.out &
[3]+ 4776 Running ./test10.sh > test10.out &
[root@master /]# kill -9 4776
[root@master /]# jobs -l
[1] 4772 Running ./test10.sh > test10.out &
[2]- 4774 Running ./test10.sh > test10.out &
[3]+ 4776 Killed ./test10.sh > test10.out
[root@master /]# jobs -l
[1]- 4772 Running ./test10.sh > test10.out &
[2]+ 4774 Running ./test10.sh > test10.out &
중단된 작업을 다시 시작하기
- Bash 작업 제어를 사용하면 중단되었던 작업을 백그라운드 프로세스나 포그랑룬드 프로세스 중 한가지 형태로 다시 시작할 수 있다. 포그라운드 프로세스는 작업하고 있는 터미널의 제어권을 넘겨받으므로 이 기능을 사용할 때 주의해야 한다.
jaehwan@DESKTOP-R2MTKGU:~$ vi hello.sh
^[[Bjaehwan@DESKTOP-R2MTKGU:~$ ./hello.sh
^Z
[1]+ 정지됨 ./hello.sh
jaehwan@DESKTOP-R2MTKGU:~$ bg
[1]+ ./hello.sh &
jaehwan@DESKTOP-R2MTKGU:~$ Hello
Worlad
Hello
jobs
[1]+ 완료 ./hello.sh
jaehwan@DESKTOP-R2MTKGU:~$ ./hello.sh &
[1] 159
jaehwan@DESKTOP-R2MTKGU:~$ fg 1
./hello.sh
Hello
Worlad
Hello
- 플러스 기호로 표시되는 기본 작업이었기 때문에 백그라운드 모드에서 다시 시작하기 위해 bg 명령이 필요했다.
- 포그라운드 모드에서 작업을 다시 시작하려면 작업 번호와 함께 fg 명령을 사용한다.
Nice 활용하기
멀티태스킹 운영체제에서 커널은 시스템에서 실행되는 각 프로세스에 대해 CPU 시간을 할당하는 책임이 있다. 스케줄링 우선순위는 다른 프로세스와 비교해서 커널이 프로세스에 할당되는 CPU 시간의 양을 뜻한다. 기본적으로 쉘에서 시작된 모든 프로세스는 리눅스 시스템에서 동일한 스케줄링 우선순위가 있다. 우선순위는 -20(가장 높은)에서 +19(가장 낮은) 사이의 정수 값이다. 기본적으로 bash 쉘은 모든 프로세스를 우선순위 0으로 실행한다.
Nice 명령 사용하기
- Nice 명령으로 실행할 때 스케줄링 우선순위를 설정할 수 있다. 명령을 낮은 우선순위로 실행시키려면 -n 커맨드라인 옵션으로 새로운 우선순위를 지정하면 된다.
- Nice 명령은 일반 시스템 사용자가 명령의 우선순위를 증가하는 것을 막는다.
- 우선순위에 음수를 부여할때 이중 대시를 써야 하므로 혼동을 피하기 위해 -n 옵션을 사용하는 것이 가장 좋다.
jaehwan@DESKTOP-R2MTKGU:~$ sudo nice -n 10 ./hello.sh > hello.out &
[3] 179
jaehwan@DESKTOP-R2MTKGU:~$ ps -p 179 -o pid,ppid,ni,cmd
PID PPID NI CMD
179 12 0 sudo nice -n 10 ./hello.sh
jaehwan@DESKTOP-R2MTKGU:~$ nice -n 10 ./hello.sh > hello.out &
[4] 181
nice: cannot set niceness: 허가 거부
jaehwan@DESKTOP-R2MTKGU:~$ sudo nice -10 ./hello.sh > hello.out &
[5] 183
Renice 명령 사용하기
- 이미 시스템에서 실행 중인 명령의 우선순위를 변경하기 위해 renice 명령이 있다. 우선순위를 변경하기 위해서 PID를 지정할 수 있다.
- Renice 명령은 실행중인 프로세스의 스케줄링 우선순위를 자동으로 업데이트 한다. (nice 명령과 마찬가지로 몇 가지 제한이 있다.)
- 소유권을 가지고 있는 프로세스에만 renice 명령 사용가능
- 낮은 우선순위로만 프로세스를 renice 가능
- 루트 사용자는 어떤 프로세스에 어떤 우선순위로든 renice 명령 가능
- 실행 중인 프로세스를 완전히 제어하려면 루트 계정으로 로그인하거나 sudo 명령을 사용한다.
jaehwan@DESKTOP-R2MTKGU:~$ ./hello.sh &
[6] 184
jaehwan@DESKTOP-R2MTKGU:~$ ps -p 184 -o pid,ppid,ni,cmd
PID PPID NI CMD
184 12 0 /bin/bash ./hello.sh
jaehwan@DESKTOP-R2MTKGU:~$ renice -n 10 -p 184
184 (process ID) old priority 0, new priority 10
jaehwan@DESKTOP-R2MTKGU:~$ ps -p 184 -o pid,ppid,ni,cmd
PID PPID NI CMD
184 12 10 /bin/bash ./hello.sh
시계처럼 정확히 실행하기
리눅스 시스템은 미리 선택된 시간에 스크립트를 실행하는 몇 가지 방법을 제공하는데 at 명령 및 크론 테이블이 그것이다. 언제 얼마나 자주 스크립트를 실행할 것인지 일정을 예약하기 위해서 서로 다른 기술을 사용한다.
at 명령을 사용하여 작업 예약하기
- at 명령으로 리눅스 시스템이 스크립트를 실행할 시간을 지정할 수 있다. at 명령은 쉘이 작업을 실행해야 할 때를 통제하는 대기열에 작업을 올리고 at 데몬인 atd는 백그라운드에서 실행되며 실행시킬 작업의 대기열을 확인한다.
- atd 데몬은 at 명령을 사용하여 대기열에 올린 작업에 대해 시스템의 특별한 디렉토리(/var/spool/at)를 검사한다. 기본적으로 atd 데몬은 이 디렉토리를 60초마다 확인한다.
at 명령 형식 이해하기
at [ -f filename] time
- ㅁ
- 리눅스 시스템 작업을 실행시키려는 시간을 매개변수로 지정한다.
- at 명령은 다양한 시간 형식을 인식한다.
- 표준 시 몇 분 형식 : 10:15
- 오전(am) / 오후(pm) 표시 : as 10:15PM
- 특정하게 이름을 붙인 시각, now(지금), noon(정오), midnight(자정) or teatime(4PM)
- 표준 날짜 형식 : MMDDYY, MM/DD/YY, DD.MM.YY
- 텍스트 날짜 : Jul 4 or Dec 25,
- 시간 증분 값 :
- Now+ 25 minutes
- 10:15PM tomorrow
- 10:15 + 7 days
- at 명령은 작업 대기열로 올라가고, 작업 대기열은 at 명령이 올린 작업들을 처리하기 위해 보관한다. 작업 대기열은 소문자 a~z, 대문자 A~Z까지 사용해서 참조된다. (알파벳 순서가 뒤로 갈수록 작업이 실행될 우선순위는 더 낮아진다.
작업 결과 얻기
- at 명령은 작업이 실행되도록 예약된 시간과 작업에 할당된 작업 번호를 표시한다. -f 옵션은 어떤 크립트 파일을 사용할 것인지 지정하고 now는 지금 당장 실행하도록 지정한다.
- at 명령은 sendmail 애플리케이션으로 이메일을 사용하지 않는다면 어떤 출력도 얻을 수 없다. 따라서 at 명령을 사용할 때 STDOUT 및 STDERR을 리다이렉트하는 것이 가장 좋다.
- at 명령으로 작업을 실행시킬 때 이메일이나 리다이렉트 중 어떤 것도 원하지 않는다면 작업이 만들어내는 출력을 억제하는 -M 옵션을 추가하는 것이 좋다.
jaehwan@DESKTOP-R2MTKGU:~$ cat test13.sh
#!/bin/bash
# Test using at command
echo "This script ran at $(date +%B%d,%T)"
echo
sleep 5
echo "This is the script's end..."
jaehwan@DESKTOP-R2MTKGU:~$ at -f test13.sh now
job 4 at Sun Dec 10 19:14:00 2017
jaehwan@DESKTOP-R2MTKGU:~$ cat test13b.sh
#!/bin/bash
# Test using at command
echo "This script ran at $(date +%B%d,%T)" > test13.out
echo >> test13b.out
sleep 5
echo "This is the script's end..." >> test13b.out
jaehwan@DESKTOP-R2MTKGU:~$ at -M -f test13b.sh now
job 7 at Sun Dec 10 19:19:00 2017
jaehwan@DESKTOP-R2MTKGU:~$ cat test13b.out
대기중인 작업 목록 보기
- atq 명령으로 시스템에 대기중인 작업 목록을 볼 수 있다.
- 작업 목록은 작업 번호, 시스템이 작업할 날짜와 시간, 작업이 저장되어 있는 작업 대기열을 보여준다.
jaehwan@DESKTOP-R2MTKGU:~$ atq
3 Sun Dec 10 19:14:00 2017 a jaehwan
4 Sun Dec 10 19:14:00 2017 a jaehwan
6 Sun Dec 10 19:19:00 2017 a jaehwan
7 Sun Dec 10 19:19:00 2017 a jaehwan
8 Mon Dec 11 16:00:00 2017 a jaehwan
작업 제거하기
- 어떤 작업이 어떤 대기열에서 대기하고 있는지에 관한 정보를 알았다면 대기중인 작업을 제거하기 위해 atrm 명령을 사용할 수 있다.
- 자신이 실행을 위해 대기열에 올린 작업만 제거할 수 있다. 다른 사람이 올린 작업은 제거할 수 없다.
jaehwan@DESKTOP-R2MTKGU:~$ atrm 3
jaehwan@DESKTOP-R2MTKGU:~$ atrm 4
jaehwan@DESKTOP-R2MTKGU:~$ atrm 6
jaehwan@DESKTOP-R2MTKGU:~$ atq
7 Sun Dec 10 19:19:00 2017 a jaehwan
8 Mon Dec 11 16:00:00 2017 a jaehwan
스크립트를 정기적으로 실행되도록 예약하기
- 리눅스 시스템은 정기적으로 실행해야 하는 작업을 예약할 수 있도록 cron 프로그램을 사용한다. Cron 프로그램은 백그라운드에서 실행되며 예약된 작업을 위한 특별한 테이블인 크론 테이블을 확인한다.
크론 테이블 보기
- 크론 테이블은 작업이 언제 실행되어야 하는지를 지정할 수 있도록 특별한 형식을 사용한다.
min hour dayofmonth month dayofweek command
- 크론 테이블 특정한 값, 값의 범위 또는 와일드카드 문자로(별표) 항목을 지정할 수 있다.
- Dayofmonth, month, and dayofweek 필드에 사용된 와일드카드 문자는 cron이 매달, 매일10:15에 명령을 실행할 것을 의미한다.
- Dayofmonth 란에는 세 글자로 된 텍스트 값(on, tue, wed, thu, fri, sat, sun) 또는 0을 일요일로 시작해서 6이 토요일인 숫자값을 쓸 수 있다.
- Dayofmonth 항목에는 한 달 중의 날짜값(1-31)을 지정한다.
- 명령 목록은 명령 또는 실행할 쉘 스크립트의 전체 명령 경로를 지정해야 한다.
- Cron 프로그램은 작업을 대기열에 올린 사용자 계정을 사용하여 스크립트를 실행한다. 따라서 명령 목록에 지정된 명령 및 풀력 파일에 접근할 수 있는 적절한 권한이 있어야 한다.
- 매달 마지막 날에 명령이 실행되도록 설정하는 방법으로 널리 쓰이는 방법은 data 명령을 사용하는 if-then문을 추가해서 다음날의 날짜값이 01인지 확인하는 것이다.
00 12 * * * if [`date +%d -d tomorrow` = 01]; then; command
크론 테이블 만들기
- 각 시스템 사용자는 에약된 작업을 실행하기 위한 자신의 크론 테이블을 가질 수 있다.
- 기본적으로 각 사용자의 크론 테이블 파일은 존재하지 않는다. 자신의 크론 테이블에 항목을 추가하려면 -e 매개변수를 사용한다.
jaehwan@DESKTOP-R2MTKGU:~$ crontab -l
no crontab for jaehwan
jaehwan@DESKTOP-R2MTKGU:~$ crontab -e
크론 디렉토리 보기
- 정확한 실행 시간을 반드시 필요로 하지는 않는 스크립트를 만든다면 미리 설정된 크론 스크립트 디렉토리 중 하나를 사용하는 것이 더 쉽다. 기본적으로 hourly, daily, monthly and weekly 이렇게 네 가지 디렉토리가 있다.
- 하루에 한번 실행되야 할 스크립트라면 daily 디렉토리에 스크리브를 복사하기만 하면 cron이 매일 실행한다.
jaehwan@DESKTOP-R2MTKGU:~$ ls /etc/cron.*ly
/etc/cron.daily:
apport dpkg mdadm popularity-contest
apt-compat logrotate mlocate update-notifier-common
bsdmainutils man-db passwd
/etc/cron.hourly:
/etc/cron.monthly:
/etc/cron.weekly:
Anacron 프로그램 살펴보기
- Cron 프로그램의 유일한 문제는 리눅스 시스템이 하루 24시간, 주 7일 내내 운영되고 있다고 가정하는 것이다. 크론 테이블에 있는 어떤 작업을 실행도록 예약된 시간에 리눅스 시스템이 꺼져 있다면 그 작업은 실행되지 않는다. 이 문제를 해결하기 위해 많은 리눅스 배포판은 anacron에 프로그램을 함께 포함한다.
- Anacron은 예약된 실행을 놓친 작업이 있는지 판단하고 될 수 있는 대로 빨리 이러한 작업을 실행한다. 리눅스가 며칠 동안 꺼져 있다가 다시 시작되었다면 꺼져 있던 시간 동안 실행되기로 예약된 모든 작업이 자동으로 실행된다.
- 이 기능은 일상적인 로그 유지 관리를 수행하는 스크립트에 사용된다. 스크립트가 실행되어야 할 때 시스템이 항상 꺼져 있다면 로그 파일은 절대로 정리되지 않고 계속 계속 커져만 갈 것이다. Anacron을 쓰면 적어도 시스템이 시작될때 마다 로그 파일이 정리될 것이라고 보장될 수 있다.
- Anacron 프로그램은 /etc/cron.monthly와 같은 cron 디렉토리에 있는 프로그램만이 대상이다. 작업이 제대로 예약된 간격으로 실행되고 있는지 확인하려면 타임스탬프를 사용하고, 각 크론 디렉토리마다 타임스탬프 파일이 하나씩 존재하고 이 파일은 /var/spool/anacron에 있다.
[root@master ~]# sudo cat /var/spool/anacron/cron.monthly
20171202
- Anacron 프로그램은 작업 디렉토리를 확인하는 자체 테이블을 가지고 있다.
- Anacron 테이블의 기본 형식은 크론 테이블과 약간 다르다
Period delay identifier command
- Period(기간)항목은 얼마나 자주 작업이 실행되어야 하는지를 날짜 수 단위로 정의한다. 이 항목을 작업의 타임스탬프 파일과 비교해서 검사한다.
- Deploy(지연)항목은 시스템이 시작되고 나서 얼마 후에(분) 프로그램이 실행되어야 할지를 지정한다.
- Command(명령어)항목은 run-parts 프로그램과 크론 스크립트 디렉토리 이름을 포함하고 있다.
- Identifier 항목은 빈 칸 없는 고유 문자열이다. 이는 고유 로그 메시지 및 오류 이메일에서 작업을 식별하는 데 사용한다.
- Anacron은 /etc/cron.hourly에 있는 스크립트는 실행하지 않는 점에 유의하라. 그 이유는 anacron 프로그램이 매일 이상으로 자주 실행해야 하는 스크립트는 처리하지 않기 때문
[root@master ~]# cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22
#period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
새로운 쉘에서 스크립트 실행하기
- 사용자가 새 bash 쉘을 실행할 때마다 스크립트를 실행시키는 기능은 편리할 수 있다. 때때로 셸 세션을 위한 기능을 쉘 기능을 설정하거나 그저 특정 파일이 설정되어 있는지 확인할 필요가 생길 수 있다.
$HOME/ .bash_profile
$HOME/ .bash_login
$HOME/ .profile
- 따라서 로그인할 때 실행할 스크립트는 모두 이 목록에서 처음 나오는 파일에 두어야 한다.
- Bash 쉘은 쉘이 시작할 때마다 .bashrc 파일을 실행한다. 홈 디렉토리의 .bashrc 파일에 간단한 echo문을 추가하고 새로운 쉘을 실행함으로써 이를 확인할 수 있다.
- Bash 파일은 보통 bash 시동 파일 중 하나에서 실행한다. Bash 쉘로 로그인을 하거나 bash 쉘을 새로 실행시킬 때 모두 .bashrc 파일이 실행되기 때문에 쉘 스크립트를 이 파일 안에 두면 된다.
[root@master ~]# cat ~/.bashrc
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias vi='vim'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
echo "I'm in a new shell!"
[root@master ~]# bash
I'm in a new shell!
[root@master ~]# exit
exit
'Programming > Shell' 카테고리의 다른 글
[Bash] 코딩 규칙 및 모범 사례 (0) 2020.01.17 [Bash] 쉘 스크립트 개요 (0) 2017.08.16