특정 시점에 단 한 번 실행되는 리눅스 작업을 설정할 때, cron은 필요 이상으로 복잡할 수 있습니다. 이때 필요한 것이 바로 `at` 계열의 명령어입니다! 시스템 자원이 충분할 때 작업을 실행하고 싶다면 `batch`를 활용할 수 있습니다.
리눅스 작업 예약 방법
cron 데몬은 특정 시간에 실행되도록 예정된 작업 목록을 관리합니다. 이러한 작업과 프로그램들은 지정된 시간에 백그라운드에서 실행되며, 반복적인 작업들을 예약하는 데 매우 유용합니다. 매 시간마다, 매일 특정 시간에, 혹은 매달 또는 매년 한 번씩 작업을 실행해야 할 때 cron을 통해 설정할 수 있습니다.
하지만 한 번만 실행해야 하는 작업을 예약하려는 경우, cron은 최적의 선택이 아닐 수 있습니다. 물론 cron을 사용할 수 있지만, 작업이 완료된 후 crontab 항목을 삭제하는 것을 잊지 않아야 하는 번거로움이 따릅니다.
리눅스 사용자라면 누군가가 이미 겪었을 법한 문제에 직면하게 될 가능성이 높습니다. 운 좋게도 유닉스 계열 운영체제는 오랜 역사를 가지고 있기 때문에 대부분의 문제에 대한 해결책이 이미 존재할 가능성이 높습니다.
앞서 설명한 문제에 대한 해결책이 이미 있으며, 그 해결책이 바로 `at`과 `batch`입니다.
at 명령어 설치
Ubuntu 18.04와 Manjaro 18.1.0에서는 설치가 필요했으며 (Fedora 31에는 이미 설치되어 있었습니다).
Ubuntu에 설치하려면 다음 명령을 사용하세요:
sudo apt-get install at
설치가 완료되면, 다음 명령어로 at 데몬을 시작할 수 있습니다:
sudo systemctl enable --now atd.service
Manjaro에서는 다음 명령어를 사용하여 설치합니다:
sudo pacman -Sy at
설치가 완료되면, 다음 명령어를 입력하여 at 데몬을 시작합니다:
sudo systemctl enable --now atd.service
모든 배포판에서 atd 데몬이 실행 중인지 확인하려면 다음 명령어를 입력하면 됩니다.
ps -e | grep atd
at 명령어 대화식 사용법
`at`을 사용하려면 실행할 날짜와 시간을 지정해야 합니다. 이 글 뒷부분에서 더 자세히 다루겠지만, 날짜와 시간을 설정하는 데에는 상당히 많은 유연성이 있습니다.
대화식으로 `at`을 사용할 때에도 날짜와 시간을 미리 제공해야 합니다. 명령줄에 날짜나 시간 정보 없이 `at`만 입력하거나 날짜/시간 형식이 아닌 다른 내용을 입력하면, 다음과 같이 “시간 왜곡”이라는 메시지가 나타납니다.
at
at banana
날짜와 시간은 명시적으로 지정하거나 상대적으로 표현할 수 있습니다. 예를 들어, 현재 시간에서 1분 후에 명령을 실행하고 싶다면 `at`은 “지금”이 무엇을 의미하는지 알고 있으므로, `now` 키워드를 사용하여 1분을 더할 수 있습니다.
at now + 1 minute
`at`은 메시지와 함께 `at` 프롬프트를 출력하고, 사용자가 예약하려는 명령어를 입력할 때까지 기다립니다. 하지만 먼저 다음 메시지에 주목해야 합니다.
이는 `at`이 `sh` 쉘의 인스턴스를 시작하여 명령어를 실행할 것임을 알려줍니다. 즉, 명령은 `sh` 쉘과 호환되어야 하며, 더 풍부한 기능을 제공하는 Bash 쉘에서는 실행되지 않을 수 있습니다.
만약 명령이나 스크립트가 Bash가 제공하는 기능이나 특징을 사용하려고 하지만, `sh`가 이를 지원하지 않는다면 작업은 실패할 수 있습니다.
명령이나 스크립트가 `sh`에서 실행되는지 여부는 쉽게 테스트할 수 있습니다. `sh` 명령어를 사용하여 `sh` 쉘을 시작합니다.
sh
명령 프롬프트가 달러 기호($)로 바뀌면 명령어를 실행하고 올바르게 작동하는지 확인할 수 있습니다.
Bash 쉘로 돌아가려면 `exit` 명령어를 입력합니다.
exit
명령어를 실행해도 표준 출력이나 오류 메시지가 화면에 표시되지 않습니다. 이는 `sh` 쉘이 백그라운드 작업으로 시작되고 어떤 종류의 화면 인터페이스 없이 실행되기 때문입니다.
좋든 싫든, 명령어의 모든 출력은 이메일로 전송됩니다. `at` 명령어를 실행한 사용자의 내부 메일 시스템을 통해 전송됩니다. 즉, 내부 이메일 시스템을 설정하고 구성해야 합니다.
많은(대부분의) 리눅스 시스템은 내부 이메일 시스템이 필요하지 않기 때문에, 시스템에 내부 메일 시스템이 없는 경우가 많습니다. 일반적으로 시스템에서 메일 발송을 위해 `sendmail`이나 Postfix와 같은 시스템을 사용합니다. 시스템에 내부 이메일 시스템이 없는 경우, 스크립트가 파일에 내용을 쓰도록 하거나 출력을 파일로 리디렉션하여 로그를 추가할 수 있습니다.
만약 명령이 표준 출력이나 오류 메시지를 생성하지 않는다면, 이메일도 받지 못합니다. 대부분의 리눅스 명령어는 아무런 메시지를 표시하지 않는 것으로 성공을 나타내므로, 대부분의 경우 이메일을 받지 못할 것입니다.
이제 `at`에 명령어를 입력할 시간입니다. 이 예에서는 *.bak, *.tmp, *.o 파일들을 삭제하는 `sweep.sh`라는 작은 스크립트 파일을 사용합니다. 아래와 같이 명령어의 경로를 입력하고 Enter 키를 누릅니다.
또 다른 명령 프롬프트가 나타나고, 원하는 만큼 명령어를 추가할 수 있습니다. 일반적으로 단일 스크립트에 여러 명령어를 포함하고 `at`에서 해당 스크립트를 호출하는 것이 더 편리합니다.
Ctrl+D를 눌러 명령어 추가를 완료했음을 알립니다. 이는
작업이 실행된 후, 내부 메일을 확인하려면 다음을 입력합니다.
만약 메일이 없다면, 작업이 성공적으로 완료된 것으로 간주해야 합니다. 물론 이 경우 *.bak, *.tmp, *.o 파일들이 삭제되었는지 확인하여 명령어가 잘 실행되었는지 확인할 수도 있습니다.
전체 과정을 다시 실행하려면 다음을 입력합니다.
at now + 1 minute
1분 후, 메일을 다시 확인하려면 다음을 입력합니다.
메일이 도착했습니다! 메시지 번호 1을 읽으려면 `1`을 입력한 다음 Enter 키를 누릅니다.
스크립트의 명령어가 오류 메시지를 생성했기 때문에 이메일이 도착했습니다. 이 예에서는 이전에 스크립트를 실행했을 때 파일들을 이미 제거했기 때문에 삭제할 파일이 없었던 것입니다.
D+Enter를 눌러 이메일을 삭제하고, Q+Enter를 눌러 메일 프로그램을 종료합니다.
날짜 및 시간 형식
`at`과 함께 사용할 수 있는 시간 형식은 매우 다양합니다. 다음은 몇 가지 예시입니다.
오전 11시에 실행:
at 11:00 AM
내일 오전 11시에 실행:
at 11:00 AM tomorrow
다음 주 같은 요일 오전 11시에 실행:
at 11:00 AM next week
이번 주, 오늘, 다음 주 같은 시간에 실행:
at next week
다음 주 금요일 오전 11시에 실행:
at 11:00 AM next fri
다음 주 금요일 같은 시간에 실행:
at next fri
다음 달 같은 날짜 오전 11시에 실행:
at 11:00 AM next month
특정 날짜 오전 11시에 실행:
at 11:00 AM 3/15/2020
지금부터 30분 후 실행:
at now + 30 minutes
지금부터 2시간 후 실행:
at now + 2 hours
내일 같은 시간에 실행:
at tomorrow
목요일 같은 시간에 실행:
at thursday
오전 12시에 실행:
at midnight
오후 12시에 실행:
at noon
영국인이라면 티타임(오후 4시)에 실행되도록 명령을 예약할 수도 있습니다.
at teatime
작업 대기열 보기
`atq` 명령어를 입력하면 아래와 같이 예약된 작업들의 대기열을 볼 수 있습니다.
대기열의 각 명령어에 대해 `atq`는 다음 정보를 표시합니다.
작업 ID
예정된 날짜
예정된 시간
작업이 위치한 대기열. 대기열은 “a”, “b” 등으로 표시됩니다. `at`으로 예약하는 일반 작업은 “a” 대기열로 이동하고, `batch`로 예약한 작업(이 글 뒷부분에서 설명)은 “b” 대기열로 이동합니다.
작업을 예약한 사용자
명령줄에서 at 사용
`at`을 반드시 대화식으로 사용할 필요는 없습니다. 명령줄에서 직접 사용할 수도 있으며, 이렇게 하면 스크립트 내에서 더욱 쉽게 활용할 수 있습니다.
다음과 같이 `at`으로 명령을 파이프할 수 있습니다:
echo "sh ~/sweep.sh" | at 08:45 AM
`at`에 의해 작업이 수락 및 예약되고, 이전과 마찬가지로 작업 번호와 실행 날짜가 표시됩니다.
명령어 파일과 함께 at 사용
파일에 일련의 명령어를 저장한 다음, `at`에 전달할 수도 있습니다. 이는 단순히 명령어가 나열된 일반 텍스트 파일일 수도 있으며, 실행 가능한 스크립트일 필요는 없습니다.
다음과 같이 `-f` (파일) 옵션을 사용하여 파일 이름을 `at`에 전달할 수 있습니다.
at now + 5 minutes -f clean.txt
파일을 다음 위치로 리디렉션하여도 동일한 결과를 얻을 수 있습니다.
at now + 5 minutes < clean.txt
대기열에서 예약된 작업 제거
예약된 작업을 대기열에서 제거하려면 `atrm` 명령어를 사용할 수 있습니다. 제거하려는 작업 번호를 먼저 확인하려면 `atq`를 사용하여 대기열을 확인한 다음, `atrm`과 함께 해당 작업 번호를 사용하면 됩니다. 아래 예시를 참고하세요:
atq
atrm 11
atq
작업 상세 정보 확인 방법
앞서 언급했듯이 작업을 미래의 특정 시점으로 예약할 수 있습니다. 가끔은 예약해둔 작업이 정확히 무엇인지 잊어버릴 수도 있습니다. `atq` 명령어는 대기열에 있는 작업들을 보여주지만, 실제로 어떤 작업을 하는지는 보여주지 않습니다. 작업의 자세한 내용을 확인하려면 `-c` (cat) 옵션을 사용할 수 있습니다.
먼저 `atq`를 사용하여 작업 번호를 확인합니다.
atq
이제 `-c` 옵션과 함께 작업 번호 13을 사용합니다.
at -c 13
다음은 작업에 대해 얻을 수 있는 정보를 분석한 결과입니다:
첫 번째 줄: 명령어가 `sh` 쉘에서 실행될 것임을 알려줍니다.
두 번째 줄: 명령어가 사용자 ID 1000과 그룹 ID 1000으로 실행된다는 것을 알 수 있습니다. 이는 `at` 명령어를 실행한 사용자의 값입니다.
세 번째 줄: 이메일을 받을 사람의 정보입니다.
네 번째 줄: 사용자 마스크가 22입니다. 이는 이 `sh` 세션에서 생성된 모든 파일에 대한 기본 권한을 설정하는 데 사용되는 마스크입니다. 마스크를 666에서 빼면 644가 됩니다(8진수 표기로 `rw-r–r–`).
나머지 데이터: 대부분 환경 변수입니다.
테스트 결과: 테스트를 통해 실행 디렉토리에 접근할 수 있는지 확인합니다. 접근할 수 없다면 오류가 발생하고 작업 실행이 중단됩니다.
실행할 명령어: 예약된 스크립트의 내용이 나열되고 표시됩니다. 위의 예시 스크립트는 Bash에서 실행되도록 작성되었지만, 여전히 `sh` 쉘에서 실행될 것입니다.
batch 명령어
`batch` 명령어는 작동 방식이 유사하지만, `at` 명령어와 세 가지 중요한 차이점이 있습니다.
`batch` 명령어는 대화식으로만 사용할 수 있습니다.
특정 시간에 실행되도록 작업을 예약하는 대신, 대기열에 추가하면 시스템 평균 부하가 1.5 미만이 될 때 `batch` 명령어가 작업을 실행합니다.
위의 이유로 `batch` 명령어에서는 날짜와 시간을 지정하지 않습니다.
`batch` 명령어를 사용할 때는 다음과 같이 명령어 매개변수 없이 이름만 입력합니다.
batch
다음으로, `at` 명령어와 마찬가지로 작업을 추가합니다.
at 명령어 접근 제어
`at.allow`와 `at.deny` 파일은 `at` 계열의 명령어를 사용할 수 있는 사용자를 제어합니다. 이 파일들은 `/etc` 디렉토리에 있습니다. 기본적으로 `at.deny` 파일만 존재하며, `at`이 설치될 때 생성됩니다.
작동 방식은 다음과 같습니다:
`at.deny`: `at`을 사용하여 작업을 예약할 수 없는 응용 프로그램 및 사용자 목록입니다.
`at.allow`: `at`을 사용하여 작업을 예약할 수 있는 사용자 목록입니다. `at.allow` 파일이 없다면, `at`은 `at.deny` 파일만 사용합니다.
기본적으로 누구나 `at`을 사용할 수 있습니다. 사용자를 제한하려면 `at.allow` 파일을 사용하여 사용할 수 있는 사용자를 명시적으로 지정하는 것이 좋습니다. `at`을 사용하지 못하도록 `at.deny` 파일에 모든 사용자를 추가하는 것보다 훨씬 간단합니다.
`at.deny` 파일 내용은 다음과 같습니다:
sudo less /etc/at.deny
이 파일에는 `at`을 사용할 수 없는 운영 체제 구성 요소들이 나열되어 있습니다. 대부분 보안상의 이유로 접근이 제한되어 있으므로, 파일에서 제거하지 않는 것이 좋습니다.
이제 `at.allow` 파일을 편집합니다. `dave`와 `mary` 사용자를 추가하고, 다른 사용자는 `at`을 사용할 수 없도록 설정합니다.
먼저 다음 명령어를 입력합니다.
sudo gedit /etc/at.allow
편집기에서 아래와 같이 두 사용자 이름을 추가한 후 파일을 저장합니다.
이제 다른 사용자가 `at`을 사용하려고 하면 권한이 없다는 메시지가 표시됩니다. 예를 들어, `eric`이라는 사용자가 다음 명령어를 입력한다고 가정해 봅시다.
at
아래와 같이 거절될 것입니다.
다시 말하지만, `eric`은 `at.deny` 파일에 존재하지 않습니다. `at.allow` 파일에 사용자를 추가하는 순간부터, 그 외의 모든 사용자는 `at`을 사용할 수 있는 권한이 거부됩니다.
일회성 작업에 적합
보시다시피 `at`과 `batch`는 모두 한 번만 실행해야 하는 작업에 적합합니다. 다시 한번 간단히 요약하자면:
정기적인 프로세스가 아닌 단발성 작업을 실행해야 할 때는 `at`으로 스케줄링합니다.
시스템 부하가 충분히 낮을 때만 작업을 실행하려면 `batch`를 사용합니다.