HP OpenVMS Systems Documentation

Content starts here

14 DCL을 사용한 고급 프로그래밍
고급 DCL 프로그래밍에는 복잡한 명령 프로시저와 PIPE 명령이 사용됩니다. 13장을 읽고 DCL 프로그래밍에 대한 기본 지식을 얻은 후 고급 프로그래밍 방법을 배우려면 이 장을 읽어야 합니다.
복잡한 명령 프로시저는 프로그램과 유사한 기능을 수행할 수 있습니다. 명령 프로시저에서 가변 입력 사용, 특정 조건이 참인 경우 프로시저의 섹션 실행, 서브 루틴 실행 또는 다른 명령 프로시저 호출 등이 가능합니다.
또한, DCL 명령인 PIPE 명령을 사용하여 프로그램과 같은 기능을 수행할 수 있습니다. 예를 들어, 동일한 DCL 명령행에서 PIPE 명령을 사용하여 다음 중 한 가지 이상의 작업을 실행할 수 있습니다.
파이프라인화(명령 순서)
입/출력 재지정
여러 명령 및 조건 명령 실행
백그라운드 처리
이 장에서는 다음 사항에 대하여 설명합니다.
명령 프로시저 입력
매개 변수를 사용하여 중첩된 명령 프로시저에 데이터 전달
명령 프로시저 출력
파일 읽기 및 쓰기(파일 I/O)
파일 I/O 오류 처리
실행 흐름 제어 방법
새로운 명령 수준 만들기
Case 문 작성
PIPE 명령 사용
명령 프로시저 입력
명령 프로시저에는 사용자가 제공하는 데이터가 필요한 경우가 많습니다. 이러한 데이터는 13장에서 설명한 것처럼 대화형으로 입력하거나 비대화형으로 제공할 수 있습니다. 이 장에서는 비대화형 입력 방법과 13장에서 설명하지 않은 다른 대화형 입력 방법에 대해 설명합니다.
특정 명령 프로시저가 실행될 때마다 동일한 데이터를 사용하려면 데이터가 필요한 명령 뒤에 오는 데이터 행의 명령 프로시저에 데이터를 포함시키십시오.
다음 명령 프로시저는 CENSUS.EXE라는 명령 프로시저를 실행합니다. CENSUS.EXE는 명령 프로시저가 실행될 때마다 1993, 1994, 1995의 데이터를 읽습니다.
$ ! CENSUS.COM
$ !
$ RUN CENSUS
1993
1994
1995
$ EXIT
명령 프로시저에 데이터 포함 시 제한 사항
데이터 행의 텍스트가 명령 프로시저에 직접 전달되므로 다음과 같이 번역되어야 할 데이터는 처리되지 않습니다.
기호
논리 이름
산술 표현식
그 밖의 데이터 입력 방법
명령 프로시저를 위한 그 밖의 데이터 입력 방법은 다음과 같습니다.
매개 변수를 사용하여 데이터 전달
매개 변수를 사용하여 일괄 처리 작업에 데이터 전달
매개 변수를 사용하여 중첩된 명령 프로시저에 데이터 전달
INQUIRE 및 READ 명령을 사용하여 데이터 프롬프트 표시
SYS$INPUT 논리 이름을 사용하여 데이터 입력
매개 변수를 사용하여 데이터 전달
데이터를 매개 변수로서 명령 프로시저에 전달할 때는 다음 지침을 따르십시오.
명령 프로시저의 파일 지정 뒤에 매개 변수를 넣으십시오.
한 명령 프로시저에 최대 8개의 매개 변수까지 전달할 수 있습니다.
8개 이하의 매개 변수를 전달할 경우에는 null 값에 별도의 기호가 할당됩니다.
null 값은 문자가 없는 문자열이며 인용 부호( ”)로 표시됩니다.
각 매개 변수는 하나 이상의 공백이나 탭으로 구분하십시오.
명령 프로시저에 전달된 매개 변수는 로컬 기호 P1에서 P8에 배치됩니다. 첫 번째 매개 변수 값에 P1, 두 번째 매개 변수 값에 P2, 세 번째에 P3 하는 식으로 할당됩니다. 예를 들어, 다음 명령은 SUM.COM 명령 프로시저를 호출하고 그 프로시저에 8개의 매개 변수를 전달합니다.
$ @SUM 34 52 664 89 2 72 87 3
매개 변수를 정수로 지정
정수를 매개 변수로 지정하면 문자열로 변환됩니다. 다음 보기에서 P1은 문자열 값 24; P2는 문자열 값 25입니다.
$ @ADDER 24 25
필요한 변환이 자동으로 수행되므로 정수와 문자열 표현식 모두 P1에서 P8 기호를 사용할 수 있습니다.
매개 변수를 문자열로 지정
문자열의 공백, 탭 또는 소문자를 그대로 유지하려면 다음 보기와 같이 문자열 전후에 인용 부호(“ ”)를 넣습니다. 예를 들면 다음과 같습니다.
$ @DATA "Paul Cramer"
다음 보기에서 P1은 Paul Cramer이고 P2는 null입니다. 인용 부호를 생략하면 다음 보기와 같이 각 문자열이 별개의 매개 변수로 전달됩니다. 예를 들면 다음과 같습니다.
$ @DATA Paul Cramer
이 보기에서는 문자열 Paul과 Cramer가 대문자로 변환되어 P1은 PAUL이고 P2는 CRAMER입니다.
다음 명령을 사용하여 DATA.COM을 호출하는 경우는 다음과 같습니다.
$ @DATA "Paul Cramer" 24 "(555) 111-1111")
DATA.COM에서 P1에서 P8는 아래와 같이 정의됩니다.
P1 = Paul Cramer
P2 = 24
P3 = (555) 111-1111
P4-P8 = null
매개 변수를 기호로 지정
매개 변수 값을 기호로 전달하려면 기호 전/후에 어포스트로피를 넣습니다. 기호 값의 공백, 탭, 소문자를 그대로 유지하려면 기호 값을 세 쌍의 인용 부호로 묶어야 합니다. 인용 부호를 문자열의 일부로 포함시킬 경우에도 세 쌍의 인용 부호를 사용해야 합니다.
텍스트를 인용 부호로 묶고 어포스트로피를 기호 앞에 두 개, 뒤에 한 개씩 넣는 방법도 있습니다.
다음 보기에서는 기호를 명령 프로시저에 전달할 때 인용 부호가 제거되었기 때문에 P1는 Paul이고 P2는 Cramer입니다.
$ NAME = "Paul Cramer"
$ @DATA 'NAME'
다음 보기에서 P1이 “Paul Cramer”이고 P2는 null입니다.
$ NEW_NAME = """Paul Cramer"""
$ @DATA 'NEW_NAME'
다음 보기에서 P1은 Paul Cramer로 변환됩니다.
$ ! DATA.COM
$ @NAME "''P1'"
매개 변수를 null 값으로 지정
null 매개 변수를 전달하려면 명령 문자열에 자리 표시자로 한 쌍의 인용 부호를 사용합니다. 다음 보기에서 DATA.COM으로 전달된 첫 번째 매개 변수는 null 매개 변수입니다.
$ @DATA "" "Paul Cramer"
이 보기에서 P1은 null, P2는 Paul Cramer입니다.
매개 변수를 사용하여 일괄 처리 작업에 데이터 전달
매개 변수를 일괄 처리 모드로 명령 프로시저에 전달하려면 SUBMIT 명령을 /PARAMETERS 한정자와 함께 사용합니다.
하나의 SUBMIT 명령을 사용하여 두 개 이상의 명령 프로시저를 실행하는 경우에는 일괄 처리 작업의 각 명령 프로시저에 대해 지정된 매개 변수가 사용됩니다.
다음 보기에서는 세 개의 매개 변수가 일괄 처리 작업으로 실행되는 ASK.COM과 GO.COM 명령 프로시저에 전달됩니다.
$ SUBMIT/PARAMETERS=(TODAY,TOMORROW,YESTERDAY) ASK.COM, GO.COM)
다음 보기에서는 두 개의 매개 변수가 LIBRARY.COM과 SORT.COM 명령 프로시저에 전달됩니다.
$ SUBMIT-
_$ /PARAMETERS=(DISK:[ACCOUNT.BILLS]DATA.DAT,DISK:[ACCOUNT]NAME.DAT) -
_$ LIBRARY.COM, SORT.COM
일괄 처리 작업은 로그인하여 각 명령 프로시저를 실행한 것처럼 실행됩니다.
이 SUBMIT 명령은 사용자 계정으로 로그인된 일괄 처리 작업을 실행하고, 로그인 명령 프로시저를 실행한 후 다음 명령을 실행합니다.
$ @LIBRARY DISK:[ACCOUNT.BILLS]DATA.DAT DISK:[ACCOUNT]NAME.DAT)
$ @SORT DISK:[ACCOUNT.BILLS]DATA.DAT DISK:[ACCOUNT]NAME.DAT)
데이터를 명령 프로시저에 포함시키거나 SYS$INPUT 파일을 정의하여 일괄 처리 작업에 데이터를 전달하는 방법도 있습니다. 일괄 처리 작업의 각 명령 프로시저에 대해 지정된 매개 변수가 사용됩니다.
매개 변수를 사용하여 중첩된 명령 프로시저에 데이터 전달
최대 8개의 매개 변수를 중첩된 명령 프로시저에 전달할 수 있습니다. 중첩된 프로시저의 P1에서 P8의 로컬 기호는 호출하는 프로시저의 P1에서 P8 로컬 기호와 관계가 없습니다.
다음 보기에서 DATA.COM은 중첩된 명령 프로시저인 NAME.COM을 호출합니다.
$ ! DATA.COM
$ @NAME 'P1' Joe Cooper
DATA.COM의 P1이 인용 부호가 없는 문자열 Paul Cramer이면 NAME.COM에 두 개의 매개 변수로 전달됩니다. NAME.COM에서 P1-P8은 다음과 같이 정의됩니다.
P1 = PAUL
P2 = CRAMER
P3 = JOE
P4 = COOPER
P5-P8 = null
DATA.COM에서 P1이 인용 부호가 있는 “Paul Cramer”이면 다음과 같이 세 쌍의 인용 부호로 묶어 하나의 매개 변수로 NAME.COM에 전달할 수 있습니다.
$ ! DATA.COM
$ QUOTE = """
$ P1 = QUOTE + P1 + QUOTE
$ @NAME 'P1' "Joe Cooper"
이 보기에서 NAME.COM 명령 프로시저의 P1은 Paul Cramer이고 P2는 Joe Cooper입니다.
데이터 프롬프트 표시
INQUIRE 명령(13장에서 설명)을 사용하거나 READ 명령을 사용하여 명령 프로시저에 필요한 데이터를 대화형으로 입력하도록 할 수 있습니다. 이 두 명령은 모두 입력을 위한 프롬프트를 표시하고 그 응답을 기호에 할당합니다.
READ 명령과 INQUIRE 명령은 다음과 같은 차이가 있습니다.
표 14-1
INQUIRE 명령
READ 명령
값을 위한 프롬프트를 표시합니다.
값을 위한 프롬프트를 표시합니다.
터미널로부터 값을 읽습니다.
첫 번째 매개 변수로 지정된 소스로부터 값을 읽습니다
값을 기호에 할당합니다.
값을 두 번째 매개 변수로서 이름이 지정된 기호에 할당합니다

READ 명령은 프롬프트에 대한 응답으로 터미널에 입력된 모든 문자를 대/소문자, 공백, 탭을 포함하여 그대로의 문자열로 받아들입니다. /PROMPT 한정자를 생략하면 기본 프롬프트인 Data:가 표시됩니다.
또한, 매개 변수를 받아들이거나 필수 매개 변수가 지정되지 않을 경우 사용자에게 입력하라는 프롬프트를 표시할 수 있는 명령 프로시저를 작성할 수 있습니다.
다음 명령은 터미널에 Filename:이라는 프롬프트를 표시하고 논리 이름인 SYS$COMMAND에 의해 지정된 소스(기본적으로 터미널)로부터 응답을 읽어 그 응답을 FILE:이라는 기호에 할당합니다.
$ READ/PROMPT="Filename: " SYS$COMMAND FILE
다음 보기에서 프로시저가 호출될 때 파일 이름이 지정되어 있지 않으면 사용자에게 파일 이름을 입력하라는 프롬프트를 표시합니다.
$ ! Prompt for a file name if name
$ ! is not passed as a parameter
$ IF P1 .EQS. "" THEN INQUIRE P1 "Filename"
$ COPY 'P1' DISK5:[RESERVED]*.*
$ EXIT
주 일괄 처리 작업으로 실행하기 위해 명령 프로시저를 제출하는 경우에는 INQUIRE 명령 뒤에 나오는 데이터 행으로부터 INQUIRE 명령에 지정된 기호의 값을 읽습니다. 데이터 행을 포함시키지 않으면 기호에는 null 값이 할당됩니다.
SYS$INPUT 논리 이름을 사용하여 데이터 입력
명령, 유틸리티 및 그 밖의 시스템 이미지는 기본 입력 스트림인 논리 이름 SYS$INPUT에 의해 지정된 소스로부터 입력 데이터를 얻습니다. 명령 프로시저에서 SYS$INPUT은 명령 프로시저 파일로 정의됩니다. 데이터를 필요로 하는 명령 또는 이미지인 경우에는 그 파일의 데이터 행에서 데이터를 검색합니다.
그러나 SYS$INPUT을 재정의하여 터미널이나 별도의 입력 파일로부터 데이터를 제공할 수 있습니다.
SYS$INPUT을 터미널로 재정의
SYS$INPUT을 터미널로 재정의하여 명령 프로시저로부터 호출된 이미지에 대화형으로 데이터를 입력할 수 있습니다.
명령 프로시저에 대화형으로 데이터를 입력해야 하는 DCL 명령이나 유틸리티를 사용하려면 SYS$INPUT을 터미널로 재정의해야 합니다.
다음 명령 프로시저는 CENSUS.EXE 이미지에 대화형으로 입력 사항을 제공할 수 있도록 합니다.
$ ! Execute CENSUS getting data from the terminal
$ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND
$ RUN CENSUS
$ EXIT
DEFINE/USER_MODE 명령은 CENSUS.EXE가 실행되는 동안 일시적으로 SYS$INPUT을 재정의하여 CENSUS.EXE에 터미널로부터 입력 사항을 제공합니다. SYS$INPUT은 CENSUS.EXE가 완료된 후 원래의 정의인 명령 프로시저 파일로 되돌아갑니다.
다음 명령 프로시저는 EVE를 텍스트 편집기로 사용합니다.
$ ! Obtain a list of your files
$ DIRECTORY
$ !
$ ! Get file name and invoke the EVE editor
$ EDIT_LOOP:
$ INQUIRE FILE "File to edit (Press Return to end)"
$ IF FILE .EQS. "" THEN EXIT
$ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND
$ EDIT/TPU 'FILE'
$ GOTO EDIT_LOOP
명령 프로시저는 사용자가 Return 키를 눌러 루프를 종료할 때까지 파일 이름을 위한 프롬프트를 표시합니다. 이 프로시저는 사용자가 파일 이름을 입력하면 파일 편집을 위해 EVE를 자동으로 호출합니다. 편집기가 실행되고 있는 동안 SYS$INPUT은 터미널로 정의되어 편집 사항을 대화형으로 입력할 수 있습니다.
SYS$INPUT을 별개의 파일로 정의
SYS$INPUT을 파일로 정의하여 파일을 통해 명령 프로시저에 입력 사항을 제공할 수 있습니다. 데이터 행은 처리되지 않는다는 점을 주의하십시오. 명령 프로시저는 데이터 행의 텍스트를 명령이나 이미지로 직접 전달하며 데이터 행에 DCL 기호나 표현식을 포함시킬 경우 기호를 값으로 대체하거나 표현식을 평가하지 않습니다. 데이터 행에 감탄 부호(!)를 사용하면 데이터를 전달받은 이미지에서 처리합니다.
또한, 데이터 파일 이름을 SYS$INPUT으로 지정하여 명령 프로시저 파일에 프로그램을 포함시킬 수 있습니다. 이렇게 하면 컴파일러가 다른 파일이 아닌 명령 프로시저에서 프로그램을 읽게 됩니다.
다음 보기에서는 프로그램 문이 뒤에 오는 FORTRAN 명령을 포함하는 명령 프로시저를 보여 줍니다.
$ FORTRAN/OBJECT=TESTER/LIST=TESTER SYS$INPUT
C THIS IS A TEST PROGRAM
A = 1
B = 2
STOP
END
$ PRINT TESTER.LIS
$ EXIT
FORTRAN 명령에서는 논리 이름인 SYS$INPUT을 사용하여 컴파일될 파일을 식별합니다. SYS$INPUT은 명령 프로시저와 같으므로 FORTRAN 컴파일러는 FORTRAN 명령 뒤의 명령문을 달러 기호로 시작하는 다음 행까지 컴파일합니다.
컴파일이 종료되면 TESTER.OBJ와 TESTER.LIS 두 개의 출력 파일이 만들어집니다.
그 다음에는 PRINT 명령이 파일을 인쇄합니다.
명령 프로시저 출력 수행
데이터, 오류 메시지, 명령행 확인과 같은 명령 프로시저로부터의 출력이 터미널이나 다른 파일로 이루어지도록 할 수 있습니다. 여기에서 설명할 출력 지정 방법은 다음과 같습니다.
데이터 표시
명령 및 이미지로부터 출력 다시 지정
명령 프로시저에서 데이터 반환
오류 메시지 다시 지정
데이터 표시
기호를 대체할 필요가 없는 몇 행으로 된 텍스트를 표시하려면 TYPE 명령을 사용합니다. TYPE 명령은 지정하는 파일의 데이터를 SYS$OUTPUT에 기록합니다.
다음 보기에서 SYS$INPUT은 데이터 파일로 지정됩니다. TYPE 명령은 그 뒤의 데이터 행에서 데이터를 읽어 터미널에 표시합니다.
$ ! Using TYPE to display lines
$ TYPE SYS$INPUT
REPORT BY MARY JONES
PREPARED APRIL 15, 2002
SUBJECT: Analysis of Tax Deductions for 2002
.
.
.
$ EXIT
기호 또는 렉시칼 함수를 포함하는 데이터를 쓰려면 WRITE 명령을 사용합니다. 데이터를 인용 부호(“ ”)로 묶지 않으면 WRITE 명령은 기호를 자동으로 대체합니다.
WRITE 명령을 사용하여 문자열을 리터럴 텍스트로 표시하려면 다음 보기처럼 문자열을 인용 부호(“ ”)로 묶습니다.
$ WRITE SYS$OUTPUT "Two files are written."
Two files are written.
문자열에 인용 부호를 포함시키려면 다음 보기처럼 두 쌍의 인용 부호(“ “ ” ”)를 사용합니다.
$ WRITE SYS$OUTPUT "Summary of ""Q & A"" Session"
Summary of "Q & A" Session
텍스트의 한 행을 두 행 이상 계속쓰려면 다음 보기처럼 더하기 기호(+)와 하이픈(-)을 사용하여 두 문자열을 연결합니다.
$ WRITE SYS$OUTPUT "Report by Mary Jones" + -
" Prepared April 15, 2002"
Report by Mary Jones Prepared April 15, 2002
WRITE 명령은 기호 대체를 자동으로 수행하고 기호의 값을 표시합니다. 문자열 내에서 기호 대체를 수행하려면 다음 보기처럼 기호를 어포스트로피로 묶습니다.
$ AFILE = "STAT1.DAT"$ BFILE = "STAT2.DAT"
$ WRITE SYS$OUTPUT "''AFILE' and ''BFILE' ready."
STAT1.DAT and STAT2.DAT ready.
이 보기에서 STAT1.DAT는 AFILE 기호로, STAT2.DAT는 BFILE 기호로 변환됩니다.
명령 및 이미지에서 출력 재지정
명령, 유틸리티, 그 외의 시스템 이미지는 논리 이름인 SYS$OUTPUT에 의해 지정된 소스에 출력 사항을 씁니다. 기본적으로 SYS$OUTPUT은 터미널에 해당합니다. 그러나 다음 중 한 가지 방법으로 출력을 다시 지정할 수 있습니다.
명령을 호출할 때 /OUTPUT 한정자를 사용합니다. /OUTPUT 한정자를 받아들이는 DCL 명령으로는 ACCOUNTING, CALL, DIRECTORY, HELP, LIBRARY, RUN (프로세스), SPAWN, 및 TYPE이 있습니다.
DEFINE/USER_MODE 명령을 사용하여 SYS$OUTPUT을 파일로 일시적으로 다시 지정합니다 .
DEFINE/USER_MODE 명령을 사용하여 SYS$OUTPUT을 일시적으로 null 장치로 정의하여 명령에서 출력하지 못하도록 합니다.
다음 명령 프로시저는 SHOW USERS 명령의 출력을 파일로 재지정합니다. 이 새로운 SYS$OUTPUT 정의는 SHOW USERS 명령 실행에만 유효합니다.
$ DEFINE/USER_MODE SYS$OUTPUT SHOW_USER.DAT
$ SHOW USERS
$ !
$ ! Process the information in SHOW_USER.DAT
$ OPEN/READ INFILE SHOW_USER.DAT
$ READ INFILE RECORD
.
.
.
$ CLOSE INFILE
$ EXIT
다음 보기에서 SYS$OUTPUT은 null 장치(NL:)로 정의됩니다.
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ APPEND NEW_DATA.DAT STATS.DAT
.
.
.
/USER_MODE 한정자는 다음 이미지가 완료될 때까지만 유효한 임시 논리 이름 할당을 만드는 데 사용됩니다. 명령이 실행된 후에는 SYS$OUTPUT이 기본 정의(일반적으로 터미널)로 되돌아갑니다.
명령 인터프리터 내에서 실행되는 DCL 명령에서의 출력을 재정의할 때는 DEFINE/USER_MODE 명령을 사용할 수 없습니다. 그 대신 DEFINE 명령을 사용하여 SYS$OUTPUT을 재정의하고 사용이 끝난 후 DEASSIGN 명령을 사용하여 그 정의를 삭제합니다.
다음 목록은 명령 인터프리터 내에서 수행되는 모든 DCL 명령 목록입니다.
표 14-2
=
ALLOCATE
ASSIGN
ATTACH
CALL
CANCEL
CLOSE
CONNECT
CONTINUE
CREATE/LOGICAL_NAME_TABLE
DEALLOCATE
DEASSIGN
DEBUG
DECK
DEFINE
DEFINE/KEY
DELETE/SYMBOL
DISCONNECT
ELSE
ENDIF
ENDSUBROUTINE
EOD
EXAMINE
EXIT
GOSUB
GOTO
IF
INQUIRE
ON
OPEN
READ
RECALL
RETURN
SET CONTROL
SET DEFAULT
SET KEY
SET ON
SET OUTPUT_RATE
SET PROMPT
SET PROTECTION/DEFAULT
SET SYMBOL/SCOPE
SET UIC
SET VERIFY
SHOW DEFAULT
SHOW KEY
SHOW PROTECTION
SHOW QUOTA
SHOW STATUS
SHOW SYMBOL
SHOW TIME
SHOW TRANSLATION
SPAWN
STOP
SUBROUTINE
THEN
WAIT
WRITE

다음 보기는 SHOW TIME 명령에서 TIME.DAT 파일로 출력을 재지정하는 데 사용되는 명령을 보여 줍니다. SYS$OUTPUT의 할당을 취소하면 기본 정의(터미널)로 되돌아갑니다.
$ DEFINE SYS$OUTPUT TIME.DAT
$ SHOW TIME
$ DEASSIGN SYS$OUTPUT
명령 프로시저에서 데이터 반환
글로벌 기호와 논리 이름은 명령 프로시저에서 호출하는 프로시저나 DCL 명령 수준에 데이터를 반환합니다. 글로벌 기호나 논리 이름은 어느 명령 수준에서나 읽을 수 있습니다.
논리 이름은 중첩된 명령 프로시저에서 호출하는 프로시저로 데이터를 반환할 수 있습니다.
다음 보기는 글로벌 할당문을 사용하여 만들어진 글로벌 기호로 값을 전달하는 방법을 보여 줍니다.
$ @DATA "Paul Cramer"$ ! DATA.COM
$ !
$ ! P1 is a full name.
$ ! NAME.COM returns the last name in the
$ ! global symbol LAST_NAME.
$ !
$ @NAME 'P1'
$ ! NAME.COM
$ ! P1 is a first name
$ ! P2 is a last name
$ ! return P2 in the global symbol LAST_NAME
$ LAST_NAME == P2
$ EXIT
$ ! write LAST_NAME to the terminal
$ WRITE SYS$OUTPUT "LAST_NAME = ''LAST_NAME'
"LAST_NAME = CRAMER
DATA.COM은 NAME.COM 명령 프로시저를 호출하여 완전한 이름을 전달합니다. NAME.COM은 성을 글로벌 기호인 LAST_NAME에 넣습니다. NAME.COM이 완료되면 DATA.COM이 계속 실행되어 LAST_NAME을 지정함으로써 성을 읽습니다. NAME.COM 명령 프로시저는 별개의 파일에 있습니다. 이 보기에서는 명확성을 위해 그 부분을 들여썼습니다.
다음 명령 프로시저에서 REPORT.COM은 보고서 이름을 읽어 그 파일 이름을 논리 이름인 REPORT_FILE로 일치시켜 REPORT_FILE에 보고서를 쓰는 프로그램을 실행합니다.
$! Obtain the name of a file and then run
$! REPORT.EXE to write a report to the file
$!
$ INQUIRE FILE "Name of report file"$ DEFINE/NOLOG REPORT_FILE 'FILE'
$ RUN REPORT
$ EXIT
다음 보기에서 REPORT.COM 명령 프로시저는 다른 프로시저에서 호출됩니다. 호출하는 프로시저는 보고서 파일을 참조하는 논리 이름 REPORT_FILE을 사용합니다.
$! Command procedure that updates data files
$! and optionally prepares reports
$!
$ UPDATE:
.
.
.
$ INQUIRE REPORT "Prepare a report [Y or N]"
$ IF REPORT THEN GOTO REPORT_SEC
$ EXIT
$!
$ REPORT_SEC:
$ @REPORT
$ WRITE SYS$OUTPUT "Report written to ", F$TRNLNM("REPORT_FILE")
$ EXIT
오류 메시지 재지정
다음 절에서는 오류 메시지 재지정 방법에 대해 설명합니다.
SYS$ERROR 재정의
기본적으로 명령 프로시저는 시스템 오류 메시지를 SYS$ERROR에 의해 표시된 파일로 보냅니다. 시스템 오류 메시지를 지정된 파일로 보내도록 SYS$ERROR를 재정의할 수 있습니다. 그러나 SYS$ERROR를 SYS$OUTPUT과 다르게 재정의하거나 SYS$ERROR를 지정하지 않고 SYS$OUTPUT를 재정의하면 표준 시스템 오류 표시 방법을 사용하는 DCL 명령과 이미지는 시스템 오류 메시지와 시스템 중대 오류 메시지를 SYS$ERROR와 SYS$OUTPUT에 모두 보냅니다. 따라서 SYS$ERROR 정의에 표시된 파일에 한 번, SYS$OUTPUT에 표시된 파일에 한 번, 오류 메시지가 두 번 표시됩니다. 성공 메시지, 정보 메시지 및 경고 메시지는 SYS$OUTPUT에 표시된 파일에만 전달됩니다. DCL 명령에서 시스템 오류 메시지 표시를 막으려면 SYS$ERROR나 SYS$OUTPUT 중 어느 하나도 터미널로 지정하지 말아야 합니다.
명령 프로시저에서 사용자 정의 이미지 중 하나를 실행하고 그 이미지가 SYS$ERROR를 참조하는 경우에는 SYS$ERROR가 SYS$OUTPUT과 다르더라도 SYS$ERROR에 의해 표시된 파일에만 시스템 오류 메시지가 전달됩니다. 표준 시스템 오류 표시 방법을 사용하는 DCL 명령과 이미지만 SYS$ERROR와 SYS$OUTPUT이 다를 때 이 두 파일에 메시지를 보냅니다.
다음 명령 프로시저는 디렉토리 이름을 매개 변수로 받아 그 디렉토리를 기본값으로 설정하고 디렉토리에 있는 파일을 제거합니다. 시스템 오류 메시지가 표시되지 않도록 일시적으로 SYS$ERROR와 SYS$OUTPUT를 null 장치로 정의합니다.
$ ! Purge files in a directory and suppress messages
$ !
$ SET DEFAULT 'P1'
$ ! Suppress messages
$ !
$ DEFINE/USER_MODE SYS$ERROR NL:
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ PURGE
$ EXIT
시스템 오류 메시지 표시 방지
SET MESSAGE 명령을 사용하여 시스템 오류 메시지가 표시되지 않도록 하는 방법도 있습니다. /NOFACILITY, /NOIDENTIFICATION, /NOSEVERITY 또는 /NOTEXT 한정자를 사용하여 장치 이름, 메시지 ID, 오류 심각도 또는 메시지 텍스트가 표시되지 않도록 할 수 있습니다.
다음 보기에서는 두 번째 SET MESSAGE 명령에 이를 때까지 장치, ID, 심각도 및 텍스트 메시지가 일시적으로 표시되지 않습니다.
$ ! Purge files in a directory and suppress system messages
$ !
$ SET DEFAULT 'P1'
$ ! Suppress system messages
$ !
$ SET MESSAGE/NOFACILITY -
/NOIDENTIFICATION -
/NOSEVERITY -
/NOTEXT
$ PURGE
$ SET MESSAGE/FACILITY -
/IDENTIFICATION -
/SEVERITY
/TEXT
$ EXIT
읽기 및 쓰기 파일(파일 I/O)
명령 프로시저에서 파일을 읽고 쓰는 기본적인 단계는 다음과 같습니다.
표 14-3
단계
작업
1
OPEN 명령을 사용하여 파일을 엽니다.
파일을 열면 파일에 논리 이름이 할당되고 읽기 파일인지 쓰기 파일인지 또는 읽고 쓰는 파일인지 여부가 지정됩니다. 이후의 READ, WRITE, CLOSE 명령에서는 이 논리 이름을 사용하여 해당 파일을 참조합니다.
2
READ 또는 WRITE 명령을 사용하여 파일에 레코드를 읽거나 씁니다.
파일에 대한 입력과 출력은 일반적으로 레코드를 읽고 처리하여 수정한 레코드를 동일한 파일이나 다른 파일에 쓰는 루프를 통해 수행됩니다.
3
CLOSE 명령을 사용하여 파일을 닫습니다.
CLOSE 명령을 포함시키지 않으면 로그아웃할 때까지 파일이 열려 있습니다.

주 SYS$INPUT, SYS$OUTPUT, SYS$COMMAND 및 SYS$ERROR 등의 영구 프로세스 파일은 별도로 읽거나 쓰지 않아도 로그인할 때 자동으로 열립니다.
다음 절에서 설명할 내용은 다음과 같습니다.
OPEN 명령 사용
파일에 쓰기
WRITE 명령 사용
READ 명령 사용
CLOSE 명령 사용
파일 수정
레코드 업데이트
새 출력 파일 만들기
파일에 레코드 추가
OPEN 명령 사용
OPEN 명령은 순차적, 상대적 또는 인덱스 순차적 파일을 엽니다. 파일은 영구 프로세스로 열려 사용자가 CLOSE 명령을 사용하여 명시적으로 닫지 않는 한 프로세스가 지속되는 동안 열려 있습니다. 파일이 열려 있는 동안에는 영구 프로세스 파일에 대한 OpenVMS RMS 제한의 대상이 됩니다.
파일을 열 때 OPEN 명령은 첫 번째 매개 변수로 지정된 논리 이름을 두 번재 매개 변수로 지정된 파일에 할당하고 그 이름을 프로세스 논리 이름 테이블에 저장합니다. 이후의 READ, WRITE, CLOSE 명령에서는 이 논리 이름을 사용하여 파일을 참조합니다.
다음 보기에서 OPEN 명령은 INFILE이라는 논리 이름을 DISK4:[MURPHY]STATS.DAT에 할당합니다.
$ OPEN/READ INFILE DISK4:[MURPHY]STATS.DAT
주 OPEN 명령의 논리 이름은 고유한 이름이라야 합니다. OPEN 명령이 작동하지 않고 틀린 점이 없는 것으로 생각되는 경우에는 OPEN 명령의 논리 이름을 변경하십시오. 논리 이름 정의를 표시하려면 SHOW LOGICAL 명령을 사용합니다.
명령 프로시저가 올바른 파일에 액세스할 수 있도록 하려면 완전한 파일 지정 방법(예: DISK4:[MURPHY]STATS.DAT)을 사용하거나 파일을 열기 전에 SET DEFAULT 명령을 사용하여 올바른 장치와 디렉토리를 지정하십시오.
또한, 공유 파일을 지정할 수 있습니다. /SHARE 한정자를 사용하여 다른 열려 있는 파일을 활성화합니다. 그 외에도 DCL 명령인 TYPE과 SEARCH를 사용하여 사용자가 공유 파일에 액세스할 수 있습니다.
OPEN/READ 명령은 파일에 논리 이름을 할당하고 레코드 포인터를 파일 시작에 둡니다. 읽기를 위해 파일을 열면 레코드를 읽을 수만 있고 쓰지는 못합니다. 레코드를 읽을 때마다 포인터가 다음 레코드로 이동합니다.
다음 명령 프로시저에서 OPEN/READ 명령은 STATS.DAT 파일을 열고 논리 이름인 INFILE을 할당합니다.
$ OPEN/READ INFILE DISK4:[MURPHY]STATS.DAT
$ READ_FILE:
$ READ/END_OF_FILE=DONE INFILE DATA
$ GOTO READ_FILE
$ DONE:
$ CLOSE INFILE
$ EXIT
새 파일에 쓰려면 OPEN/WRITE 명령을 사용합니다. OPEN/WRITE 명령은 인쇄 파일 형식의 순차적 파일을 만듭니다. 파일을 위한 레코드 형식은 레코드 헤더가 2바이트인 고정 제어 변수(VFC)입니다. /WRITE 한정자는 /APPEND 한정자와 함께 사용할 수 없습니다.
이미 존재하는 파일을 지정하는 경우 OPEN/WRITE 명령은 기존 파일보다 버전 번호가 하나 큰 새 파일을 엽니다.
다음 보기에서 명령 프로시저는 쓰기를 위해 사용할 수 있는 새 파일 NAMES.DAT를 만듭니다.
$ OPEN/WRITE OUTFILE DISK4:[MURPHY]NAMES.DAT
$ UPDATE:
$ INQUIRE NEW_RECORD "Enter name"
$ WRITE OUTFILE NEW_RECORD
$ IF NEW_RECORD .EQS. "" THEN GOTO EXIT_CODE
$ GOTO UPDATE
$ EXIT_CODE:
$ CLOSE OUTFILE
$ EXIT
OPEN/APPEND 명령은 기존 파일 끝에 레코드를 추가합니다. 존재하지 않는 파일을 열려고 하면 오류가 발생하고 파일이 열리지 않습니다. /APPEND 한정자는 /WRITE 한정자와 함께 사용할 수 없습니다.
다음 보기에서는 기존 파일인 NAMES.DAT의 끝에 레코드가 추가됩니다.
$ OPEN/APPEND OUTFILE DISK4:[MURPHY]NAMES.DAT
$ INQUIRE NEW_RECORD "Enter name"$ WRITE OUTFILE NEW_RECORD
.
.
.
$ CLOSE OUTFILE
OPEN/READ/WRITE 명령은 파일의 처음에 레코드 포인트를 두어 첫 레코드를 읽을 수 있도록 합니다. 이 방법을 사용하여 파일을 열면 가장 최근에 읽었던 레코드만 대체할 수 있고 파일의 끝에 새 레코드를 쓸 수 없습니다. 그 외에도 수정된 레코드의 크기가 교체되는 레코드의 크기와 꼭 같아야 합니다.
다음 보기에서는 레코드 포인터가 STATS.DAT 파일의 시작에 있어서 첫 번째 레코드를 읽을 수 있습니다.
$ OPEN/READ/WRITE FILE DISK4:[MURPHY]STATS.DAT
파일에 쓰기
파일에 쓰려면 다음 절차를 사용하십시오.
표 14-4
단계
작업
1
쓰기 위해 파일을 엽니다.
2
레이블을 사용하여 쓰기 루프를 시작합니다.
파일 I/O는 단일 레코드를 쓰거나 읽는 경우가 아니면 항상 루프로 수행됩니다.
3
쓰여질 데이터를 읽습니다.
INQUIRE 명령이나 READ 명령을 사용하여 데이터를 기호로 읽어 들입니다.
4
데이터를 테스트합니다.
데이터를 포함한 기호를 점검합니다. 기호가 null이면(예: Return키를 누르고 그 행에 데이터를 입력하지 않은 경우) 파일에 쓰여질 데이터의 끝에 이르렀으며 루프의 끝으로 가야 합니다. 그렇지 않으면 계속합니다.
5
데이터를 파일에 씁니다.
WRITE 명령을 사용하여 기호의 값(한 개의 레코드)을 파일에 씁니다.
6
루프의 시작으로 돌아갑니다.
파일에 쓸 데이터가 없을 때까지 루프 내에 있어야 합니다.
7
루프를 끝내고 파일을 닫습니다.

다음 명령 프로시저는 새 파일 STATS.DAT에 데이터를 씁니다. 그 이름의 파일이 존재하지 않는 경우에는 새 버전이 만들어집니다.
$ ! Write a file
$ ON ERROR THEN EXIT ! Exit if the command
$ ! ! procedure cannot
$ ! ! open the file
$ OPEN/WRITE IN_FILE DISK4:[MURPHY]STATS.DAT ! Open the file
$ ON CONTROL_Y THEN GOTO END_WRITE ! Close the file if you
$ ! ! quit execution with
$ ! ! Ctrl/Y
$ ON ERROR THEN GOTO END_WRITE ! Close the file if an
$ ! ! error occurs
$WRITE: ! Begin the loop
$ INQUIRE STUFF "Input data" ! Prompt for input
$ IF STUFF .EQS. "" THEN GOTO END_WRITE ! Test for the end of
$ ! ! the file
$ WRITE IN_FILE STUFF ! Write to the file
$ GOTO WRITE ! Go to the beginning
$END_WRITE: ! End the loop
$ ! !
$ CLOSE IN_FILE ! Close the file
고유한 이름의 파일 만들기
고유한 이름의 파일을 만들려면 렉시칼 함수인 F$SEARCH를 사용하여 디렉토리에 이미 존재하는 이름인지 확인해야 합니다. F$SEARCH에 대한 자세한 내용은 OpenVMS DCL Dictionary의 렉시칼 함수에 대한 설명을 참조하십시오.
다음 명령 프로시저는 사용자에게 파일 이름을 입력하라는 프롬프트를 표시한 다음 F$SEARCH 렉시칼 함수를 사용하여 기본 디렉토리에 있는 이름인지 검색합니다. 이미 존재하는 이름의 파일인 경우에는 ERROR_1으로 제어가 전달되어 “The file already exists”라는 메시지를 표시한 후 GET_NAME 레이블로 제어를 반환한 후 다음 보기에 나타난 것처럼 다른 파일 이름을 입력하도록 프롬프트가 표시됩니다.
$ ! FILES.COM
$ !
$GET_NAME:
$ INQUIRE FILE "File" ! Prompt the user for a file name
$ IF F$SEARCH (FILE) .NES. "" ! Make sure the file name is unique
$ THEN
$ WRITE SYS$OUTPUT "The file already exists"$ GOTO GET_NAME
$ ELSE
$ OPEN/WRITE IN_FILE 'FILE' ! Open the file with WRITE access
$ ENDIF
.
.
.
$ EXIT
WRITE 명령 사용
다음 절에서는 WRITE 명령 사용 방법에 대해 설명합니다.
데이터 지정
WRITE 명령을 위해 데이터를 지정할 때는 12장에서 설명한 문자열 표현식 규칙을 따르십시오. 다음과 같은 방법으로 데이터를 지정할 수 있습니다.
문자열 표현식으로 쓰여질 데이터를 지정합니다. WRITE 명령은 기호와 렉시칼 함수를 자동으로 대체합니다.
문자열을 리터럴 문자열로 출력 파일에 씁니다. WRITE 명령은 인용 부호로 묶인 문자열에 대해서는 기호 대체를 수행하지 않습니다.
리터럴 문자열을 기호 이름과 결합합니다. 기호 대체를 강제 실행하려면 문자열 전체를 인용 부호 안에 넣고 어포스트로피를 기호 앞에 두 개, 뒤에 한 개 넣어 식별합니다.
리터럴 문자열을 기호 이름과 결합하는 다른 방법은 다음 보기처럼 기호 앞과 뒤에 쉼표를 삽입하고 구분된 기호 주위에 인용 부호를 넣고 문자열 전체를 인용 부호로 묶는 것입니다.
$ WRITE OUTFILE "Count is ",COUNT,"."
WRITE 명령행에 어포스트로피를 사용하여 기호 대체를 강제 실행합니다.
어포스트로피를 사용하여 리터럴 문자열과 렉시칼 함수를 결합하여 문자열 내에서 기호 대체를 강제 실행합니다.
보기
$! Define symbols
$!
$ CREATED = "File created April 15, 2002"
$ COUNT = 4
$ P4 = "fourth parameter"
$!
$! Open the file DATA.OUT for writing
$!
$ OPEN/WRITE OUTFILE DISK4:[MURPHY]DATA.OUT
$!
$ WRITE OUTFILE CREATED [1]
$ WRITE OUTFILE "CREATED" [2]
$!
$ WRITE OUTFILE "Count is ''COUNT'." [3]
$ WRITE OUTFILE P'COUNT' [4]
$!
$ WRITE OUTFILE "Mode is ''f$mode()'" [5]
$!
$ CLOSE OUTFILE


$ TYPE DISK4:[MURPHY]DATA.OUT Return [6]
File created April 15, 2002
CREATED
Count is 4.
fourth parameter
Mode is INTERACTIVE
$

위의 보기에서 주목할 사항은 다음과 같습니다.
[1] 문자열 표현식으로 쓰여질 데이터를 지정합니다.
[2] 문자열 CREATED를 리터럴 문자열로 출력 파일에 씁니다.
[3] 리터럴 문자열을 기호 이름과 결합합니다.
[4] WRITE 명령행에 어포스트로피를 사용하여 기호 대체를 강제 실행합니다. 이 보기에서 WRITE 명령은 COUNT 기호를 값으로 대체하고 그 결과인 문자열(P4)에 대해 기호 대체를 수행합니다.
[5] 리터럴 문자열과 렉시칼 함수를 결합합니다.
[6] 앞에 나오는 WRITE 명령에 의해 출력 파일 DATA.OUT에 쓰여진 데이터를 표시합니다.
/SYMBOL 한정자 사용
WRITE 명령은 레코드를 쓰고 레코드 포인터를 그 레코드 다음으로 이동합니다.
WRITE 명령을 사용하여 2,048바이트 길이의 레코드까지 쓸 수 있습니다.
다음 조건 중 하나가 존재하는 경우에는 레코드를 쓸 때 /SYMBOL 한정자를 사용하십시오.
레코드가 1,024바이트보다 긴 경우
WRITE 명령에 있는 표현식이 255바이트보다 긴 경우
긴 레코드 쓰기에 대한 자세한 내용은 OpenVMS DCL Dictioanry의 WRITE 명령에 대한 설명을 참조하십시오.
/UPDATE 한정자 사용
새 레코드를 삽입하는 것이 아니라 레코드를 변경하는 경우에는 WRITE 명령을 /UPDATE 한정자와 함께 사용할 수 있습니다. /UPDATE 한정자를 사용하려면 읽기와 쓰기를 모두 할 수 있도록 파일을 열어야 합니다.
READ 명령 사용
레코드를 읽고 그 내용을 기호에 할당하려면 READ 명령을 사용합니다. READ 명령을 사용하여 길이가 1,024자 이하인 레코드를 읽을 수 있습니다. 파일에서 데이터를 읽으려면 다음 절차를 사용하십시오.
표 14-5
단계
작업
1
읽기를 위해 파일을 엽니다.
2
레이블을 사용하여 읽기 루프를 시작합니다.
파일 I/O는 단일 레코드를 쓰거나 읽는 경우가 아니면 항상 루프로 수행됩니다.
3
파일에서 데이터를 읽습니다.
READ 명령을 /END_OF_FILE 한정자와 함께 사용하여 레코드를 읽고 그 내용을 기호에 할당합니다. /END_OF_FILE 한정자를 사용하면 파일 끝에 도달할 때 /END_OF_FILE 한정자에 의해 지정된 레이블로 제어가 전달됩니다. 일반적으로 사용자가 읽기 루프의 끝을 표시하는 레이블을 지정합니다.
4
데이터를 처리합니다.
파일을 순차적으로 읽을 때는 현재 레코드를 다음 레코드를 읽기 전에 처리합니다.
5
루프의 처음으로 돌아갑니다.
파일 끝에 이를 때까지 루프에 남아 있습니다.
6
루프를 종료하고 파일을 닫습니다.

다음 명령 프로시저는 STATS.DAT 파일의 각 레코드를 읽고 처리합니다. end-of-file 상태가 반환될 때까지 READ 명령을 반복하여 실행한 다음 END_READ라는 레이블이 있는 행으로 분기됩니다.
$ OPEN/READ INFILE DISK4:[MURPHY]STATS.DAT !Open the file
$ !
$READ_DATA: !Begin the loop
$ READ/END_OF_FILE=END_READ INFILE RECORD !Read a record; test for
$ ! end of file
$ ! Process the data
.
.
.
$ GOTO READ_DATA !Go to the beginning
$ ! of the loop
$END_READ: !End of loop
$ CLOSE INFILE !Close the file
$ EXIT
READ 명령을 위한 기호 이름을 지정하면 명령 인터프리터에서 그 이름을 현재 명령 수준의 로컬 기호 테이블에 저장합니다. 두 개 이상의 READ 명령을 위해 동일한 기호 이름을 사용하는 경우에는 각 READ 명령이 기호 이름 값을 재정의합니다. 예를 들어, 앞의 보기에서 READ 명령은 루프를 통과할 때마다 입력 파일인 STATS.DAT에서 새 레코드를 읽은 다음 이 레코드를 사용하여 RECORD 기호의 값을 재정의합니다.
/END_OF_FILE 한정자 사용
파일에서 읽을 때는 일반적으로 파일 끝에 도달할 때까지 각 레코드를 읽고 처리합니다. /END_OF_FILE 한정자를 READ 명령과 함께 사용하여 파일에서 레코드를 읽고 처리한 다음 모든 레코드를 다 읽으면 종료되는 루프를 구성할 수 있습니다.
/END_OF_FILE 한정자를 위해 지정하는 레이블에는 GOTO 명령을 위해 지정된 레이블과 동일한 규칙이 적용됩니다. GOTO 명령에 대한 자세한 내용은 13장을 참조하십시오.
READ 명령을 루프에서 사용할 때는 항상 /END_OF_FILE 한정자를 사용해야 합니다. 그렇지 않으면 OpenVMS RMS(Record Management Services)에서 end-of-file을 나타내는 오류 조건이 반환될 때 명령 인터프리터에서 현재 ON 명령에 의해 지정된 오류 조치를 수행합니다. 예를 들어, OpenVMS RMS에서 %RMS-E-EOF 오류 상태를 반환하면 명령 프로시저에서 자체적으로 오류를 처리하지 않는 한 그 프로시저는 종료됩니다.
/INDEX 및 /KEY 한정자 사용
인덱스된 순차적 파일에서 레코드를 임의로 읽으려면 READ 명령을 /INDEX 및 /KEY 한정자와 함께 사용합니다. 이 두 한정자는 인덱스에서 지정된 키를 찾아 그 키와 연관된 레코드를 반환함으로써 파일에서 레코드를 읽도록 지정합니다. 인덱스를 지정하지 않으면 기본 인덱스(0)가 사용됩니다.
레코드를 임의로 읽은 후 READ 명령을 /KEY 또는 /INDEX 한정자 없이 사용하여 파일의 나머지 부분을 순차적으로 읽을 수 있습니다.
/DELETE 한정자 사용
READ 명령과 함께 /DELETE 한정자를 사용하여 인덱스된 순차적 파일에서 레코드를 삭제할 수 있습니다. /DELETE 한정자를 사용하면 레코드를 읽은 후 그 레코드가 파일에서 삭제됩니다. 주어진 키에 의해 지정된 레코드를 삭제하려면 /DELETE 한정자를 /INDEX 및 /KEY 한정자와 함께 사용합니다.
/DELETE, /INDEX 및 /KEY 한정자에 대한 자세한 내용은 OpenVMS DCL Dictionary의 READ 명령에 대한 설명을 참조하십시오.
Close 명령 사용
CLOSE 명령을 사용하여 파일을 닫고 OPEN 명령으로 만들어진 논리 이름의 할당을 취소합니다. 명령 프로시저를 종료하기 전에 명령 프로시저에서 연 모든 파일을 닫아야 합니다. 열린 파일을 닫지 않으면 명령 프로시저를 종료할 때 파일이 열린 채로 남게 되고 그 열린 파일에 할당된 논리 이름이 프로세스 논리 이름 테이블에서 삭제되지 않습니다.
다음 보기에서 CLOSE 명령은 STATS.DAT 파일을 닫고 논리 이름인 INFILE의 할당을 취소합니다.
$ OPEN INFILE DISK4:[MURPHY]STATS.DAT
.
.
.
$ CLOSE INFILE
파일 수정
이 절에서는 다음 세 가지 파일 수정 방법에 대해 설명합니다.
레코드 업데이트
새 출력 파일 만들기
레코드 추가
레코드 업데이트
레코드를 업데이트하여 수정할 때는 파일에 있는 적은 수의 레코드에 대해 간단한 사항을 변경할 수 있습니다. 이 방법으로는 파일의 레코드 크기나 레코드 수를 변경할 수 없으므로 데이터 파일과 같이 형식화된 레코드가 있는 파일의 경우에만 이 방법을 사용하십시오.
파일에서 간단한 사항을 변경하려면 다음 절차를 사용하십시오.
표 14-6
단계
작업
1
읽기와 쓰기가 가능하도록 파일을 엽니다.
2
READ 명령을 사용하여 수정하려는 레코드에 도달할 때까지 파일을 읽습니다.
3
레코드를 수정합니다.
순차적 파일에서는 이 레코드 텍스트의 크기가 원래 레코드와 꼭같아야 합니다. 수정한 레코드의 텍스트가 더 짧은 경우에는 원래 레코드와 같은 길이가 될 때까지 끝에 공백을 추가하십시오. 수정한 레코드 텍스트가 더 긴 경우에는 새 파일을 만들어야 합니다.
4
WRITE/UPDATE 명령을 사용하여 수정한 레코드를 파일에 다시 씁니다.
5
변경하려는 모든 레코드를 변경할 때까지 2 단계와 4 단계를 반복합니다.
6
CLOSE 명령을 사용하여 파일을 닫습니다.
레코드가 변경되었지만 파일의 버전 번호는 파일을 닫은 후에도 달라지지 않습니다.

다음 명령 프로시저는 레코드를 개별적으로 읽고 업데이트하여 순차적 파일을 수정하는 방법을 보여 줍니다.
$! Open STATS.DAT and assign it the logical name FILE
$!
$ OPEN/READ/WRITE FILE DISK4:[MURPHY]STATS.DAT
$ BEGIN_LOOP:
$! Read the next record from FILE into the symbol RECORD
$ READ/END_OF_FILE=END_LOOP FILE RECORD
$! Display the record and see if the user wants to change it
$! If yes, get the new record. If no, repeat loop
$!
$ PROMPT:
$ WRITE SYS$OUTPUT RECORD
$ INQUIRE/NOPUNCTUATION OK "Change? Y or N [Y] "
$ IF OK .EQS. "N" THEN GOTO BEGIN_LOOP
$ INQUIRE NEW_RECORD "New record"
$! Compare the old and new records
$! If old record is shorter than new record, issue an
$! error message. If old record and new record are the
$! same length, write the record. Otherwise pad the new
$! record with spaces so it is correct length
$!
$ OLD_LEN = F$LENGTH(RECORD)
$ NEW_LEN = F$LENGTH(NEW_RECORD)
$ IF OLD_LEN .LT. NEW_LEN THEN GOTO ERROR
$ IF OLD_LEN .EQ. NEW_LEN THEN GOTO WRITE_RECORD
$ SPACES = " "
$ PAD = F$EXTRACT(0,OLD_LEN-NEW_LEN,SPACES)
$ NEW_RECORD = NEW_RECORD + PAD
$!
$ WRITE_RECORD:
$ WRITE/UPDATE FILE NEW_RECORD
$ GOTO BEGIN_LOOP
$!
$ ERROR:
$ WRITE SYS$OUTPUT "Error -- New record is too long"
$ GOTO PROMPT
$!
$ END_LOOP:
$ CLOSE FILE
$ EXIT
시스템에서는 레코드를 터미널에 표시하고 사용자에게 수정할 것인지 묻습니다. 레코드를 수정하기로 선택하는 경우에는 새 레코드를 터미널에서 읽어 원래 레코드와 길이를 비교합니다. 원래 레코드의 길이가 더 길면 새 레코드에 공백을 추가하여 같은 크기로 만듭니다. 원래 레코드가 더 짧으면 오류 메시지가 표시되고 새 레코드를 위한 프롬프트가 다시 나타납니다.
새 출력 파일 만들기
파일의 많은 부분을 변경하려면 해당 파일을 읽기 액세스를 위해 열고 새 파일을 쓰기 액세스를 위해 엽니다. 새 출력 파일을 만드는 것이므로 레코드 크기를 변경하거나 레코드를 추가, 삭제 또는 삽입할 수 있습니다.
OPEN/WRITE 명령을 사용하여 새 파일을 쓰기 액세스를 위해 엽니다. 새 파일은 원래 파일 이름과 같은 이름을 사용할 수 있으며 버전 번호는 이전 파일보다 하나 위로 합니다.
주 올바른 파일을 열어서 읽도록 하려면 쓰기 액세스를 위한 새 버전을 열기 전에 읽기 액세스를 위해 기존 파일을 먼저 열어야 합니다.
수정할 수 있는 파일을 만들려면 다음 절차를 사용하십시오.
표 14-7
단계
작업
1
읽기 액세스를 위해 파일을 엽니다.
이 파일은 수정하려는 입력 파일입니다.
2
쓰기 액세스를 위해 새 파일을 엽니다.
이 파일은 새로 만드는 출력 파일입니다. 출력 파일에 입력 파일과 같은 이름을 사용하는 경우에는 출력 파일의 버전 번호가 입력 파일보다 하나 위가 됩니다.
3
READ 명령을 사용하여 수정하려는 파일의 각 레코드를 읽습니다.
원래 파일에서 각 레코드를 읽을 때 처리 방법을 결정합니다.
4
레코드를 끝까지 읽고 처리합니다.
5
CLOSE 명령을 사용하여 입력 파일과 출력 파일을 모두 닫습니다.

다음 표에서 RECORD 기호는 원래 파일에서의 레코드 읽기를 포함합니다.
표 14-8
레코드 상태
처리 방법
Not changed
같은 기호를 새 파일에 씁니다.
Changed
INQUIRE 명령을 사용하여 다른 레코드를 기호에 읽어들인 다음 수정한 기호를 새 파일에 씁니다.
Deleted
기호를 새 파일에 쓰지 않습니다.
Inserted
루프를 사용하여 레코드를 기호로 읽어들이고 그 기호를 새 파일에 씁니다.

보기: 레코드 수정
다음 보기에서는 NEW_FILE 기호가 새 파일에 쓰여집니다.
$ ! No change
$ WRITE NEW_FILE RECORD
다음 보기에서는 INQUIRE 명령을 사용하여 수정한 기호를 새 파일에 씁니다.
$ ! Change
$ INQUIRE NEW_RECORD "New record"
$ WRITE NEW_FILE NEW_RECORD
다음 보기에서는 루프를 사용하여 기호를 새 파일에 씁니다.
$ ! Insertion
$LOOP:
$ !Get new records to insert
$ INQUIRE NEW_RECORD "New record"
$ IF RECORD .EQS. "" THEN GOTO END_LOOP
$ WRITE NEW_FILE NEW_RECORD
$ GOTO LOOP
$END_LOOP:
보기: 출력 파일 만들기
다음 보기는 입력 파일에서 레코드를 읽고 처리하여 출력 파일에 복사하는 명령 프로시저를 보여 줍니다.
$! Open STATS.DAT for reading and assign it
$! the logical name INFILE
$! Open a new version of STATS.DAT for writing
$! and assign it the logical name OUTFILE
$!
$ OPEN/READ INFILE DISK4:[MURPHY]STATS.DAT
$ OPEN/WRITE OUTFILE DISK4:[MURPHY]STATS.DAT
$!
$ BEGIN_LOOP:
$! Read the next record from INFILE into the symbol RECORD
$!
$ READ/END_OF_FILE=END_LOOP INFILE RECORD
$! Display the record and see if the user wants to change it
$! If yes, get the new record
$! If no, write record directly to OUTFILE
$!
$ PROMPT:
$ WRITE SYS$OUTPUT RECORD
$ INQUIRE/NOPUNCTUATION OK "Change? Y or N [Y] "
$ IF OK .EQS. "N" THEN GOTO WRITE_RECORD
$ INQUIRE RECORD "New record"$!
$ WRITE_RECORD:
$ WRITE OUTFILE RECORD
$ GOTO BEGIN_LOOP
$!
$! Close input and output files
$ END_LOOP:
$ CLOSE INFILE
$ CLOSE OUTFILE
$ EXIT
파일에 레코드 추가
기존 파일의 끝에 레코드를 추가하려면 다음 명령 프로시저(OPEN/APPEND 명령)를 사용하십시오.
표 14-9
단계
작업
1
OPEN 명령을 /APPEND 한정자와 함께 사용하여 레코드 포인터가 파일 끝에 위치하도록 합니다.
/APPEND 한정자를 사용하면 파일의 새 버전이 만들어지지 않습니다.
2
WRITE 명령을 사용하여 새 데이터 레코드를 씁니다.
3
레코드를 계속 추가합니다.
4
CLOSE 명령을 사용하여 파일을 닫습니다.

다음 명령 프로시저는 STATS.DAT 파일 끝에 레코드를 추가합니다.
$! Open STATS.DAT to append files and assign
$! it the logical name FILE
$!
$ OPEN/APPEND FILE DISK4:[MURPHY]STATS.DAT
$!
$ BEGIN_LOOP:
$! Obtain record to be appended and place this
$! record in the symbol RECORD
$!
$ PROMPT:
$ INQUIRE RECORD -
"Enter new record (press RET to quit) "
$ IF RECORD .EQS. "" THEN GOTO END_LOOP
$! Write record to FILE
$!
$ WRITE FILE RECORD
$ GOTO BEGIN_LOOP
$!
$! Close FILE and exit
$!
$ END_LOOP:
$ CLOSE FILE
$ EXIT
파일 I/O 오류 처리
시스템 오류 메시지가 표시되지 않도록 하고 지정된 레이블로 제어를 전달하려면 /ERROR 한정자를 OPEN, READ 또는 WRITE 명령과 함께 사용합니다. 입력 또는 출력 작업 중에 오류가 발생하면 /ERROR 한정자는 READ 명령에 대한 /END_OF_FILE 한정자 외의 모든 다른 오류 제어 방법을 무시합니다.
다음 보기에서는 /ERROR 한정자를 OPEN 명령과 함께 사용합니다.
$ OPEN/READ/ERROR=CHECK FILE CONTINGEN.DOC
.
.
.
$ CHECK:
$ WRITE SYS$OUTPUT "Error opening file"
OPEN 명령은 CONTINGEN.DOC 파일을 읽기 위해 열도록 요청합니다. 파일을 열 수 없는 경우(예: 파일이 없는 경우)에는 오류 상태를 반환하고 CHECK 레이블로 제어를 전달합니다.
/ERROR 한정자에 의해 지정된 오류 경로는 명령 수준에 대한 현재의 ON 상태를 무시합니다. 오류가 발생하고 대상 레이블에 성공적으로 제어가 전달되면 예약된 글로벌 기호인 $STATUS에 오류 코드가 보관됩니다. 오류 처리 루틴에 F$MESSAGE 렉시칼 함수를 사용하여 $STATUS의 메시지를 표시할 수 있습니다.
다음 보기에서는 렉시칼 함수인 F$MESSAGE를 사용하여 F$STATUS 렉시칼의 내용을 표시합니다.
$ OPEN/READ/ERROR=CHECK FILE 'P1'
.
.
.
$ CHECK:
$ ERR_MESSAGE = F$MESSAGE($STATUS)
$ WRITE SYS$OUTPUT "Error opening file: ",P1
$ WRITE SYS$OUTPUT ERR_MESSAGE
.
.
.
기본 오류 조치
사용자가 오류 조치를 지정하지 않고 OPEN, READ, WRITE 또는 CLOSE 명령을 사용하는 동안 오류가 발생할 경우에는 현재 ON 명령 조치가 취해집니다.
READ 명령 실행 시 end-of-file 메시지를 표시하는 오류 조치는 다음과 같은 경로로 결정된 것입니다.
/END_OF_FILE 한정자를 사용한 경우에는 지정된 레이블로 제어가 전달됩니다.
/END_OF_FILE 한정자를 사용하지 않은 경우에는 /ERROR 한정자를 사용하여 지정한 레이블로 제어가 전달됩니다.
/END_OF_FILE이나 /ERROR 한정자를 지정하지 않은 경우에는 현재 ON 명령 조치가 취해집니다.
실행 흐름 제어 방법
명령 프로시저의 정상적인 실행 흐름은 순차적입니다. 즉, 프로시저의 명령들이 파일 끝에 도달할 때까지 순서대로 실행됩니다. 그러나, 특정 명령문 실행 여부나 프로시저를 계속 실행할 조건을 제어할 수 있습니다.
다음 절에서 설명하는 내용은 아래와 같습니다.
실행 흐름을 제어 또는 변경하는 데 사용하는 DCL 명령
IF, THEN, ELSE
GOTO
GOSUB
CALL
명령 블록 사용
Case 문 작성
루프 작성
IF 명령 사용
IF 명령을 사용하여 표현식 값을 검사하고 표현식 결과가 참(true)일 때 명령이나 명령 블록을 실행합니다. 표현식 결과가 거짓(false)이면 다음 중 한 가지 결과가 발생합니다.
THEN 명령 뒤에 하나의 명령이 나오면 그 명령이 실행되지 않고 그 다음에 나오는 명령이 실행됩니다.
THEN 명령 뒤에 명령 블록이 나오고 ELSE 명령이 지정되어 있지 않으면 ENDIF 명령 바로 뒤에 나오는 명령이 실행됩니다.
ELSE 명령이 지정되어 있으면 ELSE 명령 뒤에 나오는 명령이나 명령 블록이 실행됩니다.
DCL에서 제공하는 IF 명령은 두 가지 형식이 있습니다. 첫 번째 형식은 13장에서 설명한 것처럼 IF 명령에 지정된 표현식이 참일 때 단일 명령을 실행하는 것입니다.
두 번째 IF 형식은 블록 구조 형식입니다. 블록 구조의 IF 명령은 지정된 표현식이 참이고 ELSE 문이 있는 경우 두 개 이상의 명령을 실행합니다. ELSE 문은 표현식이 거짓인 경우 하나 이상의 명령을 실행합니다.
THEN 명령 사용
표현식이 참일 때 두 개 이상의 명령을 실행하려면 THEN 명령을 동사(앞에 달러 기호가 있는 DCL 명령)로 지정하고 ENDIF 문을 사용하여 결과 블록 구조 문을 종료합니다.
다음 보기에서는 THEN 문이 동사로 사용됩니다.
$ IF expression
$ THEN
$ command
$ command
.
.
.
$ ENDIF
ELSE 명령 사용
표현식이 거짓일 때 한 개 이상의 명령을 실행하려면 ELSE 문을 동사로 지정하고 ENDIF 문을 사용하여 결과 블록 구조 문을 종료합니다.
다음 보기에서는 ELSE 명령이 동사로 사용됩니다.
$ IF expression
$ THEN
$ command
$ command
.
.
.
$ ELSE
$ command
$ command
.
.
.
$ ENDIF
명령 블록 사용
명령 블록은 같은 명령 프로시저에 명령을 둘 것인지 아니면 다른 명령 프로시저에 두고 거기서 실행할 것인지에 따라 몇 가지 방법으로 실행할 수 있습니다. 다음 지침을 따르십시오.
명령을 그 명령 프로시저에 그대로 두는 경우에는 다음 보기처럼 THEN 문 다음에 넣습니다.
$ IF condition
$ THEN command
command
.
.
.
$ ENDIF
명령을 별개의 프로시저에 두려면 다음 보기처럼 그 명령 프로시저에 대한 호출을 THEN 문의 일부로 만듭니다.
$ IF condition
$ THEN @command_procedure
$ ELSE command
$ command
$ ENDIF
다음 보기처럼 블록 구조가 아닌 IF 형식을 지정하고 지정된 조건에 부합되면 레이블 영역으로 가도록 할 수 있습니다.
$ IF not condition THEN GOTO END_LABEL
.
.
.
$END_LABEL:
IF 표현식의 결과가 참이면 THEN 명령 다음에 오는 명령 블록을 실행할 수 있습니다. 명령 블록을 사용할 때는 THEN 명령을 IF 명령 뒤의 행에 첫 번째 명령으로 둡니다.
다음 보기에서는 두 개의 SET TERMINAL 명령이 실행되고 F$MODE가 INTERACTIVE”일 때 PROCEED 레이블로 제어가 전달됩니다. F$MODE가 INTERACTIVE”가 아닐 때는 프로시저가 종료됩니다.
$ IF F$MODE () .EQS. "INTERACTIVE"$ THEN
$ SET TERMINAL/DEVICE=VT320
$ SET TERMINAL/WIDTH=132
$ GOTO PROCEED
$ ENDIF
$ EXIT
$PROCEED:
다음 보기는 IF 명령을 ELSE 명령과 함께 사용할 때 명령 블록을 사용하는 방법을 보여 줍니다.
$ INQUIRE DEV "Device to check"
$ IF F$GETDVI(DEV, "EXISTS")
$ THEN
$ WRITE SYS$OUTPUT "The device exists."
$ SHOW DEVICE 'DEV'
$ SET DEVICE/ERROR_LOGGING 'DEV'
$ ELSE
$ WRITE SYS$OUTPUT "The device does not exist."
$ WRITE SYS$OUTPUT "Error logging has not been enabled."
$ ENDIF
$ EXIT
조건이 참이면 SYS$OUTPUT에 메시지가 쓰여지고 SHOW DEVICE와 SET DEVICE 명령이 실행됩니다. 조건이 참이 아니면 SYS$OUTPUT에 두 개의 메시지가 쓰여집니다.
IF-THEN-ELSE 구조를 사용할 때는 다음 제한 사항을 지키십시오.
중첩된 IF 문의 수준은 15개를 넘으면 안됩니다.
THEN 문으로 시작되는 명령 블록은 ELSE 문이나 ENDIF 문으로 끝냅니다.
ELSE 문으로 시작되는 명령 블록은 ENDIF 문으로 끝냅니다.
THEN 문을 IF 문 뒤에 첫번째 실행문으로 포함시킵니다.
THEN 문이나 ELSE 문을 포함하는 행에 레이블을 지정하지 않도록 합니다. 그러나 ENDIF 문을 포함하는 행에는 레이블을 지정할 수 있습니다. 명령 블록 내에서 분기할 수 있지만 다른 명령 블록 중간으로 분기하는 것은 삼가하는 것이 좋습니다.
참(True) 표현식
IF 명령 뒤의 표현식은 논리, 산술 또는 문자열 연산자로 구분된 한 개 이상의 숫자 상수, 문자열 리터럴, 기호 이름, 또는 렉시칼 함수로 이루어질 수 있습니다. 다음 중 한 값을 가지는 표현식은 참입니다.
홀수 정수 값
Y, y, T, 또는 t로 시작하는 문자열 값
홀수 값 정수인 숫자를 포함하는 문자열 값(예: 문자열 27”)
거짓(False) 표현식
다음 중 한 값을 가지는 표현식은 거짓입니다.
짝수 정수 값
Y, y, T, 또는 t 이외의 글자로 시작하는 문자열 값
짝수 값 정수인 숫자를 포함하는 문자열(예: 문자열 28”)
표현식 작성
IF 명령을 위한 표현식을 작성할 때는 다음 규칙을 따르십시오.
IF 문에 기호를 사용하면 그 값이 자동으로 대체됩니다. 반복 변환을 강제 실행하지 않는 한 어포스트로피(')를 대체 연산자로 사용하지 않습니다.
문자열 비교 연산자는 S자로 끝납니다. 예를 들면, .EQS., .LTS., 및 .GTS와 같은 연산자를 사용하여 문자열을 비교합니다. 이에 비해 .EQ., .LT., 및 .GT. 연산자는 정수를 비교하는 데 사용됩니다.
두 문자열이 같은 지 검사할 때는 대/소문자 사용이 같아야 일치를 찾을 수 있습니다. 즉, 문자열 COPY”는 문자열 copy”나 CoPy”와 다릅니다.
다음 보기는 IF 명령과 함께 사용할 수 있는 표현식을 보여 줍니다. 다른 보기는 OpenVMS DCL Dictionary의 IF 명령에 대한 설명을 참조하십시오.
첫 번째 보기에서는 논리 연산자를 사용하며 THEN 문 다음에 오는 하나의 명령만 실행합니다. CONT 기호가 참이 아니면 프로시저가 종료됩니다.
$ INQUIRE CONT "Do you want to continue [Y/N]"
$ IF .NOT. CONT THEN EXIT
.
.
.
다음 보기에서는 IF 표현식에 하나의 기호와 하나의 레이블을 사용합니다.
$ INQUIRE CHANGE "Do you want to change the record [Y/N]"
$ IF CHANGE THEN GOTO GET_CHANGE
.
.
.
$ GET_CHANGE:
.
.
.
CHANGE 기호가 참이면 GET_CHANGE 레이블로 제어가 전달됩니다.
그렇지 않으면 IF 문 뒤에 나오는 명령이 실행됩니다.
다음 보기에서는 두 개의 다른 IF 명령을 보여 줍니다.
$ COUNT = 0
$ LOOP:
$ COUNT = COUNT + 1
$ IF COUNT .EQ. 9 THEN EXIT
$ IF P'COUNT' .EQS. "" THEN EXIT
.
.
.
$ GOTO LOOP
첫 번째 IF 명령은 두 개의 정수를 비교하고 두 번째 IF 명령은 두 개의 문자열을 비교합니다. 정수 비교에는 .EQ. 연산자를, 문자열 비교에는 .EQS. 연산자를 사용합니다.
먼저 COUNT 값을 정수 9와 비교하여 값이 같으면 프로시저를 종료하고 값이 다르면 프로시저를 계속합니다. 8개(최대 허용 수)의 매개 변수를 처리한 후 루프를 종료합니다.
두 번째 IF 표현식에서는 P'COUNT' 기호의 문자열 값을 null 문자열과 비교하여 기호가 정의되어 있지 않은지 확인합니다. COUNT 기호의 반복 대체를 강제 실행하려면 어포스트로피를 사용해야 합니다. 예를 들어, COUNT가 2이면 첫 번째 변환 결과는 P2이며 P2의 값이 문자열 비교에 사용됩니다.
IF 문의 결과가 참일 때 별개의 명령 프로시저를 실행할 수도 있습니다. 다음 보기에서는 IF 표현식의 결과가 참일 때 EXIT_ROUTINE.COM 명령 프로시저를 실행합니다.
$ GET_COMMAND_LOOP:
$ INQUIRE COMMAND -
"Enter command (DELETE, DIRECTORY, EXIT, PRINT, PURGE, TYPE)"
$ IF COMMAND .EQS. "EXIT" THEN @EXIT_ROUTINE
GOTO 명령 사용
GOTO 명령은 명령 프로시저에서 레이블 있는 행으로 제어를 전달합니다. 레이블 사용에 대한 자세한 내용은 13장을 참조하십시오. GOTO 명령은 프로시저를 정방향 또는 역방향으로 분기시키는 THEN 문에서 특히 유용합니다. 예를 들어, 명령 프로시저에서 매개 변수를 사용할 때 프로시저 시작에서 매개 변수를 테스트하고 해당 레이블로 분기할 수 있습니다.
GOTO 또는 GOSUB 명령의 대상 레이블은 별개의 IF-THEN-ELSE 구조나 별개의 서브 루틴 안에 있을 수 없습니다
다음 보기에서 IF 명령은 P1이 null 문자열이 아닌지 확인합니다.
$ IF P1 .NES. "" THEN GOTO OKAY
$ INQUIRE P1 "Enter file spec"$ OKAY:
$ PRINT/COPIES=10 'P1'
.
.
.
P1이 null 문자열이면 GOTO 명령은 실행되지 않고 INQUIRE 명령이 매개 변수 값을 위한 프롬프트를 표시합니다. 그렇지 않으면 INQUIRE 명령을 건너 뛰어 분기됩니다. 어느 경우든 OKAY 레이블이 있는 행 다음의 PRINT 명령이 실행됩니다.
다음 보기에서 GOTO 명령은 그 대상 (TEST_1)이 IF-THEN 구조 내에 있기 때문에 오류 메시지를 반환합니다.
$ GOTO TEST_1
$ EXIT
$ IF 1.EQ.1
$ THEN WRITE SYS$OUTPUT "What are we doing here?"
$ TEST_1:
$ WRITE SYS$OUTPUT "Got to the label"
$ ENDIF
$ EXIT
재실행 방지
GOTO 명령을 사용하여 성공적으로 완료된 작업의 일부를 재실행하는 것을 방지할 수 있습니다. 이를 수행하려면 다음 단계를 따르십시오.
표 14-10
단계
작업
1
프로시저의 각 가능한 시작 지점을 레이블로 시작하십시오.
2
레이블 다음에 SET RESTART_VALUE = label-name 명령을 사용하여 재시작 지점을 그 레이블로 설정합니다.
SET RESTART_VALUE = label-name 명령이 실행된 후 일괄 처리 작업이 중단된 경우 일괄 처리 작업이 다시 시작될 때 해당 레이블 이름이 글로벌 기호인 BATCH$RESTART에 할당됩니다.
3
프로시저 시작에서 $RESTART 기호의 값을 테스트합니다.
$RESTART가 참이면 BATCH$RESTART를 전달 레이블로 사용하여 GOTO 문을 실행합니다.

$RESTART 글로벌 기호
$RESTART는 시스템에서 유지 관리하는 예약된 글로벌 기호입니다. $RESTART는 일괄 처리 작업이 중단되었다가 다시 시작된 경우에는 참이고 그렇지 않은 경우에는 거짓입니다. 예약된 글로벌 기호인 $RESTART는 삭제할 수 없습니다.
명령 프로시저에 SET RESTART_VALUE 명령이 있지만 그 작업을 전부 재실행하지 않으려면 SET ENTRY/NOCHECKPOINT 명령을 입력하여 글로벌 기호인 BATCH$RESTART를 삭제합니다. 중단되었던 작업을 다시 시작할 경우에는 중단되었던 섹션에서 작업이 실행되기 시작합니다.
다음 명령 프로시저는 일괄 처리 작업에서 재시작 값을 사용하는 방법을 보여 줍니다.
$ ! Set default to the directory containing
$ ! the file to be updated and sorted
$ SET DEFAULT DISK1:[ACCOUNTS.DATA84]
$
$ ! Check for restarting
$ IF $RESTART THEN GOTO 'BATCH$RESTART'
$
$ UPDATE_FILE:
$ SET RESTART_VALUE = UPDATE_FILE
.
.
.
$ SORT_FILE:
$ SET RESTART_VALUE = SORT_FILE
.
.
.
EXIT
이 명령 프로시저를 재시작할 수 있는 일괄 처리 작업으로 제출하려면 작업을 제출할 때 SUBMIT 명령에 /RESTART 한정자를 사용합니다. 중단되었던 작업은 중단되었던 섹션에서 실행되기 시작하므로 이 작업이 SORT_FILE 루틴 중에 중단된 경우에는 재시작할 때 SORT_FILE 레이블에서 실행을 시작합니다.
시스템 실패 시에는 대부분의 프로세스 환경이 유지되지 않습니다. 시스템 실패 시에도 유지 관리되는 기호는 $RESTART와 BATCH$RESTART 뿐입니다.
그러므로, 각 SET RESTART_VALUE 명령 다음이나 $RESTART가 참인 경우 실행되는 THEN 블록에 사용된 기호나 프로세스 논리 이름은 재정의해야 합니다. 기호와 논리 이름을 THEN 블록에서 정의하는 경우에는 GOTO 'BATCH$RESTART' 명령이 THEN 블록의 마지막 명령이라야 합니다.
GOSUB 및 RETURN 명령 사용
GOSUB 명령은 명령 프로시저에서 레이블 있는 서브 루틴으로 제어를 전달합니다. 명령 프로시저에 레이블이 없는 경우에는 프로시저 실행이 계속될 수 없으며 강제 종료됩니다. 레이블에 대한 자세한 정보는 13장을 참조하십시오. 프로시저 수준 당 16번까지 GOSUB 명령을 중첩할 수 있습니다.
GOSUB 명령은 로컬 서브 루틴 호출이므로 새로운 프로시저 수준을 만들지 않습니다. 결과적으로 현재 명령 수준에 정의된 모든 레이블과 로컬 기호를 GOSUB를 사용하여 호출한 서브 루틴에서 사용할 수 있습니다.
RETURN 명령은 서브 루틴을 종료하고 GOSUB 명령 뒤에 나오는 명령으로 제어를 반환합니다. RETURN 명령을 사용하여 DCL에서 $STATUS에 할당한 값을 무시하는 $STATUS 값을 서브 루틴 끝에 지정할 수 있습니다. 이 값은 0부터 4 사이의 정수이거나 이에 해당하는 표현식이라야 합니다. $STATUS 값을 사용자가 지정하는 경우 DCL에서는 이 값을 조건 코드로 해석합니다. $STATUS 값을 지정하지 않으면 $STATUS의 현재 값이 저장됩니다.
다음 보기는 GOSUB 명령을 사용하여 서브 루틴에 제어를 전달하는 방법을 보여 줍니다.
$!
$! GOSUB.COM
$!
$ SHOW TIME
$ GOSUB TEST1 [1]
$ WRITE SYS$OUTPUT "GOSUB level 1 has completed successfully."
$ SHOW TIME
$ EXIT
$!
$! TEST1 GOSUB definition
$!
$ TEST1:
$ WRITE SYS$OUTPUT "This is GOSUB level 1."
$ GOSUB TEST2 [2]
$ RETURN %X1 [3]
$!
$! TEST2 GOSUB definition
$!
$ TEST2:
$ WRITE SYS$OUTPUT "This is GOSUB level 2."$ WAIT 00:00:02
$ RETURN [4]
위의 보기에서 주목할 사항은 다음과 같습니다.
[1] 첫 번째 GOSUB 명령은 TEST1 레이블이 붙은 서브 루틴으로 제어를 전달합니다.
[2] 프로시저는 서브 루틴 TEST1의 명령을 실행하여 TEST2 레이블이 있는 서브 루틴으로 분기합니다.
[3] 서브 루틴 TEST1의 RETURN 명령은 주 명령 프로시저로 제어를 반환하고 성공적인 완료를 나타내는 1이라는 값을 $STATUS에 전달합니다.
[4] 서브 루틴 TEST2의 RETURN 명령은 서브 루틴 TEST1에 제어를 반환합니다. 이 명령이 3번 명령 전에 실행된다는 점에 주목하십시오.
새 명령 수준 만들기
새로운 명령 수준을 만드는 방법은 다음 두 가지입니다.
한 명령 프로시저 안에 다른 명령 프로시저를 호출하는 실행 프로시저(@) 명령을 사용하여 명령 프로시저를 중첩시키는 방법(13장 참조)
CALL 명령을 사용하여 명령 프로시저 내에 있는 서브 루틴을 호출하는 방법
CALL 명령 사용
CALL 명령은 명령 프로시저에서 레이블 있는 서브 루틴으로 제어를 전달하고 새 프로시저 수준을 만듭니다. CALL 명령을 사용하여 단일 파일에서 두 개 이상의 관련된 명령 프로시저를 두어 관리하기 쉽도록 할 수 있습니다. 서브 루틴 레이블에는 고유한 이름을 사용해야 하며 명령 프로시저의 CALL 명령 앞이나 뒤에 둘 수 있습니다. 서브 루틴 레이블을 입력하는 방법은 13장을 참조하십시오.
레이블 외에 최대 8개의 선택 매개 변수를 서브 루틴에 전달할 수 있습니다. 매개 변수에 대한 자세한 내용은 매개 변수를 사용하여 데이터 전달을 참조하십시오.
CALL 명령을 사용하기 위한 규칙은 다음과 같습니다.
SYS$OUTPUT에 출력을 보냅니다.
출력을 서브 루틴에서 파일로 보낼 수 있는 /OUTPUT 한정자가 있습니다.
출력 파일에는 기본 파일 형식인 .LIS를 사용합니다.
출력 파일 지정에 와일드카드 문자를 사용할 수 없습니다.
CALL 명령 기본값
CALL 명령 사용과 관련된 추가 기본값은 다음과 같습니다.
CALL 명령을 사용하여 호출한 서브 루틴과 실행 프로시저(@) 명령을 사용하여 호출한 프로시저를 최대 32개의 명령 수준까지 중첩시킬 수 있습니다.
바깥쪽 수준에 정의된 로컬 기호는 SET SYMBOL 명령을 사용하여 마스크한 경우가 아니면 안쪽 프로시저나 서브 루틴 수준에서 사용할 수 있습니다. 글로벌 기호는 어느 명령 수준에서나 사용할 수 있습니다.
레이블은 정의된 수준에 대해서만 유효합니다.
서브 루틴 시작 및 종료
CALL 서브 루틴의 시작과 끝은 SUBROUTINE과 ENDSUBROUTINE 명령으로 정의합니다. 서브 루틴에 대한 진입 지점을 정의하는 레이블은 SUBROUTINE 명령 바로 앞에 나옵니다. ENDSUBROUTINE 명령 바로 앞에 EXIT 명령을 넣을 수는 있지만 서브 루틴을 종료할 필요는 없습니다. ENDSUBROUTINE 명령은 서브 루틴을 종료하고 CALL 명령 바로 뒤에 나오는 명령행으로 제어를 전달합니다.
서브 루틴의 명령행은 그 서브 루틴이 CALL 명령을 사용하여 호출된 경우에만 실행됩니다. 명령 프로시저의 명령행을 차례로 실행하는 동안 명령어 인터프리터는 SUBROUTINE과 ENDSUBROUTINE 명령 사이의 모든 명령을 건너뜁니다.
서브 루틴 진입 지점의 범위와 레이블 참조 사용 범위를 정의할 때는 다음과 같은 제한 사항이 적용됩니다.
다른 서브 루틴 안에 정의된 서브 루틴 진입점은 그 서브 루틴에 대해 로컬입니다. 서브 루틴 진입점이 별개의 서브 루틴 블록 내에 있는 경우에는 서브 루틴을 호출할 수 없습니다.
서브 루틴 진입점이 IF-THEN-ELSE 블록 내에 있는 경우에는 IF-THEN-ELSE 블록 밖에서 이 서브 루틴을 호출할 수 없습니다.
모든 SUBROUTINE 명령에는 서브 루틴을 끝내는 ENDSUBROUTINE 명령이 있어야 합니다.
다음 보기에서는 CALL BAR 명령이 MAIN 서브 루틴 밖에 있기 때문에 호출이 유효하지 않습니다.
$ CALL BAR
$
$ MAIN: SUBROUTINE
$
$ BAR: SUBROUTINE
$ ENDSUBROUTINE
$
$ ENDSUBROUTINE
이 CALL 명령이 제대로 이루어지려면 SUBROUTINE과 ENDSUBROUTINE 지점 내에 있어야 합니다.
다음 보기의 호출은 IF-THEN-ELSE 블록 안에 있기 때문에 허용되지 않습니다.
$ IF 1
$ THEN
$ BOB:SUBROUTINE
$ ENDSUBROUTINE
$ ENDIF
$ CALL BOB
다음 보기에는 SUB1와 SUB2라는 이름의 두 서브 루틴이 포함되어 있습니다. 서브 루틴은 CALL 명령을 사용하여 호출하기까지는 실행되지 않습니다.
$
$! CALL.COM
$
$! Define subroutine SUB1.
$!
$ SUB1: SUBROUTINE
.
.
.
$ CALL SUB2 !Invoke SUB2 from within SUB1.
.
.
.
$ @FILE !Invoke another command procedure file.
.
.
.
$ EXIT
$ ENDSUBROUTINE !End of SUB1 definition.
$!
$! Define subroutine SUB2.
$!
$ SUB2: SUBROUTINE
$ EXIT
$ ENDSUBROUTINE !End of SUB2 definition.
$!
$! Start of main routine. At this point, both SUB1 and SUB2
$! have been defined but none of the previous commands have
$! been executed.
$!
$ START:
$ CALL/OUTPUT=NAMES.LOG SUB1 "THIS IS P1"
.
.
.
$ CALL SUB2 "THIS IS P1" "THIS IS P2"
.
.
.
$ EXIT !Exit this command procedure file.
CALL 명령은 SUB1 서브 루틴을 호출하고 출력을 NAMES.LOG 파일로 지정합니다. 서브 루틴 SUB1은 서브 루틴 SUB2를 호출합니다. 프로시저에서는 SUB2를 실행하고 실행 프로시저(@) 명령을 사용하여 명령 프로시저인 FILE.COM을 호출합니다. SUB1의 모든 명령이 실행되면 주 프로시저의 CALL 명령이 SUB2를 두 번째로 호출합니다. SUB2 실행이 끝나면 프로시저가 종료됩니다.
Case 문 작성
Case 문은 변수나 표현식의 값에 따라 일련의 명령 블록 중 한 명령 블록을 실행하는 특수한 형태의 조건 코드입니다. 일반적으로 Case 문의 유효값은 각 명령 블록의 처음에 있는 레이블입니다. Case 문은 GOTO 문에서 지정된 값을 대상 레이블로 사용하여 해당 코드 블록에 제어를 전달합니다.
Case 문을 작성하려면 다음과 같이 해야 합니다.
1. 레이블을 나열합니다.
2. Case 문을 작성합니다.
3. 명령 블록을 작성합니다.
레이블 나열
레이블을 나열하려면 기호를 슬래시 또는 구분 기호로 선택한 임의의 문자를 사용하여 구분한 레이블의 목록을 포함하는 문자열과 일치시킵니다. 이 기호 정의는 명령 블록 앞에 있어야 합니다.
다음 보기에서는 COMMAND_LIST 기호가 PURGE, DELETE 및 EXIT 레이블과 동일합니다.
$ COMMAND_LIST = "/PURGE/DELETE/EXIT/"
Case 문 작성
Case 문을 작성하려면 다음 절차를 따르십시오.
표 14-11
단계
작업
1
INQUIRE 명령을 사용하여 Case 변수의 값을 가져옵니다.
2
F$LOCATE와 F$LENGTH를 IF 명령과 함께 사용하여 Case 변수의 값이 유효한 지 여부를 확인합니다.
3
변수가 유효한 경우에는 GOTO 명령을 사용하여 Case 문을 실행하여 해당 코드 블록으로 제어를 전달합니다.
그렇지 않으면 메시지를 표시하고 종료하거나 다른 Case 값을 요청합니다.

다음 보기에서는 레이블이 전체 명령 이름과 일치됩니다. 그러므로 F$LOCATE는 구분 기호를 명령 이름 검색에 포함시켜 명령 이름이 축약되지 않도록 합니다.
$GET_COMMAND:
$ INQUIRE COMMAND -
"Command (EXIT,PURGE,DELETE)"
$ IF F$LOCATE ("/"+COMMAND+"/",COMMAND_LIST) .EQ. -
F$LENGTH (COMMAND_LIST) THEN GOTO ERROR_1
$ GOTO 'COMMAND'
.
.
.
$ERROR_1:
$ WRITE SYS$OUTPUT "No such command as ''COMMAND'."
$ GOTO GET_COMMAND
명령 블록 작성
각 명령 블록에는 한 개 이상의 명령이 포함될 수 있습니다. 각 명령 블록은 고유한 레이블로 시작하고 명령 블록 목록 밖에 있는 레이블에 제어를 전달하여 끝냅니다.
다음 보기에서 각 명령 블록은 고유한 레이블인 PURGE:와 DELETE:로 시작하며 현재 명령 블록 밖의 GOTO GET_COMMAND 레이블에 제어를 전달함으로써 끝납니다.
$GET_COMMAND:
.
.
.
$PURGE:
$ INQUIRE FILE
$ PURGE 'FILE'
$ GOTO GET_COMMAND
$ !
$DELETE:
$ INQUIRE FILE
$ DELETE 'FILE'
$ GOTO GET_COMMAND
$ !
$EXIT:
루프 작성
명령 블록 처음에서 변수를 테스트하는 루프를 작성할 수 있습니다(13장 참조). 그러나 다음 절차를 따라 루프의 끝에서 종료 변수를 테스트하는 루프를 작성할 수도 있습니다.
표 14-12
단계
작업
1
루프를 시작합니다.
2
루프 본문의 명령을 수행합니다.
3
종료 변수를 변경합니다.
4
종료 변수를 테스트합니다.
조건에 부합되지 않는 경우에는 루프의 처음으로 갑니다.
5
루프를 끝냅니다.

루프 끝에서 종료 변수를 테스트할 때는 종료 변수의 값에 관계 없이 루프 본문의 명령이 최소한 한 번씩 실행된다는 점에 주의하십시오.
다음 보기의 명령 블록은 둘 다 COMMAND가 "EX" (EXIT)와 일치할 때 종료되는 루프를 실행합니다. F$EXTRACT는 COMMAND를 처음 두 자만 남기고 자릅니다. 첫 번째 보기에서는 종료 변수인 COMMAND를 루프 처음에 테스트하고 두 번째 보기에서는 루프 끝에 테스트합니다.
$ ! EXAMPLE 1
$ !
$GET_COMMAND:
$ INQUIRE COMMAND-
"Command (EXIT,DIRECTORY,TYPE,PURGE,DELETE,COPY)"
$ COMMAND = F$EXTRACT(0,2,COMMAND)
$ IF COMMAND .EQS. "EX" THEN GOTO END_LOOP
.
.
.
$ GOTO GET_COMMAND
$END_LOOP:
$ ! EXAMPLE 2
$ !
$GET_COMMAND:
$ INQUIRE COMMAND-
"Command (EXIT,DIRECTORY,TYPE,PURGE,DELETE,COPY)"$ COMMAND = F$EXTRACT(0,2,COMMAND)
.
.
.
$ IF COMMAND .NES. "EX" THEN GOTO GET_COMMAND
$ ! End of loop
지정된 횟수 만큼 루프를 수행하려면 계수기를 종료 변수로 사용하십시오. 다음 보기에서는 사용자가 입력한 10개의 파일 이름이 로컬 기호인 FIL1, FIL2, ..., FIL10에 저장됩니다.
$ NUM = 1 ! Set counter
$LOOP: ! Begin loop
$ INQUIRE FIL'NUM' "File" ! Get file name
$ NUM = NUM + 1 ! Update counter
$ IF NUM .LT. 11 THEN GOTO LOOP ! Test for termination
$END_LOOP: ! End loop
.
.
.
다음 보기에서는 계수기를 사용하여 루프를 실행하는 횟수를 제어합니다. 루프는 10회 실행되며 종료 변수는 루프 끝에서 테스트됩니다.
$! Obtain 10 file names and store them in the
$! symbols FILE_1 to FILE_10
$!
$ COUNT = 0
$ LOOP:
$ COUNT = COUNT + 1
$ INQUIRE FILE_'COUNT' "File"
$ IF COUNT .LT. 10 THEN GOTO LOOP
$!
$ PROCESS_FILES:
.
.
.
COUNT 기호는 루프가 실행되는 횟수를 기록하는 데 사용됩니다. 또한, COUNT를 사용하여 FILE_1, FILE_2 하는 식으로 FILE_10까지 기호 이름을 만듭니다. COUNT의 값은 루프 시작에서 증가되지만 테스트는 루프 끝에서 이루어진다는 점에 주의하십시오. 그러므로 COUNT가 9에서 10으로 증가될 때 루프는 FILE_10 값을 얻어 IF 문에서 거짓 결과를 발견하기 전에 마지막으로 실행됩니다.
알려진 값 순서를 위해 루프를 수행하려면 F$ELEMENT 렉시칼 함수를 사용하십시오. F$ELEMENT 렉시칼 함수는 구분 기호를 사용하여 구분한 항목 목록에서 항목을 가져옵니다. 항목 번호, 항목 구분 기호 및 목록을 F$ELEMENT의 인수로 제공해야 합니다.
F$ELEMENT 렉시칼 함수 사용 방법에 대한 자세한 내용은 OpenVMS DCL Dictionary를 참조하십시오.
다음 보기에서는 CHAP1, CHAP2, CHAP3, CHAPA, CHAPB, 및 CHAPC 파일이 순서대로 처리됩니다.
$ FILE_LIST = "1,2,3,A,B,C"$ INDEX = 0
$PROCESS:
$ NUM = F$ELEMENT(INDEX,",",FILE_LIST)
$ IF NUM .EQS. "," THEN GOTO END_LOOP
$ FILE = "CHAP''NUM'"$ ! process file named by FILE
.
.
.
$ INDEX = INDEX + 1
$ GOTO PROCESS
$END_LOOP:
$ EXIT
다음 보기에서 명령 프로시저는 루프를 사용하여 FILE_LIST 기호에 나열된 파일을 다른 노드의 디렉토리에 복사합니다.
$ FILE_LIST = "CHAP1/CHAP2/CHAP3/CHAP4/CHAP5"
$ NUM = 0
$!
$! Process each file listed in FILE_LIST
$ PROCESS_LOOP:
$ FILE = F$ELEMENT(NUM,"/",FILE_LIST)
$ IF FILE .EQS. "/" THEN GOTO DONE
$ COPY 'FILE'.MEM MORRIS::DISK3:[DOCSET]*.*
$ NUM = NUM + 1
$ GOTO PROCESS_LOOP
$!
$ DONE:
$ WRITE SYS$OUTPUT "Finished copying files."
$ EXIT
F$ELEMENT 렉시칼 함수는 첫 번째로 CHAP1, 두 번째로 CHAP2 하는 식으로 파일을 반환합니다. 루프를 한 번 거칠 때마다 NUM 값이 증가되어 다음 파일 이름을 가져옵니다. F$ELEMENT에서 슬래시가 반환되면 FILE_LIST의 모든 항목이 처리되었고 루프가 종료됩니다.
PIPE 명령 사용
PIPE 명령은 같은 명령행에서 두 개 이상의 DCL 명령 문자열을 실행합니다. PIPE 명령을 사용하여 명령 파이프라인화, 입/출력 재지정, 조건 및 백그라운드 실행과 같은 UNIX 스타일 명령 처리를 수행할 수 있습니다.
이러한 명령 처리 스타일은 호스트와 대상 시스템에 일정 형태의 파이프라인 명령 구문 분석이 예상되는 인터넷 소프트웨어 개발 및 사용을 지원합니다.
다음 절에서는 PIPE 명령을 사용하여 DCL 명령을 실행하는 방법, PIPE 명령 중단 방법 및 하위 프로세스 성능 향상 방법에 대해 보기를 들어 설명합니다.
PIPE 명령에 대한 자세한 내용은 OpenVMS DCL Dictioanry: N-Z를 참조하십시오.
하나의 PIPE 명령에 여러 개의 DCL 명령을 지정할 수 있습니다. 지정한 DCL 명령들은 순차적으로 실행됩니다. 다음 형식을 사용하십시오.
PIPE command-sequence ; command-sequence [; command-sequences]...
조건 명령 실행을 위한 PIPE 명령 사용
명령 순서는 앞에 나온 명령 순서의 실행 결과에 따라 조건부로 실행됩니다. 다음 형식을 사용하십시오.
PIPE command-sequence1 && command-sequence2
command-sequence2는 command-sequence1이 성공적으로 실행된 경우에만 실행됩니다. 다음 형식을 사용하는 경우에는 command-sequence1이 실패하는 경우에만 command-sequence2가 실행됩니다.
PIPE command-sequence1 || command-sequence2
파이프라인 실행을 위한 PIPE 명령 사용
파이프라인은 파이프에 의해 연결된 일련의 파이프라인 세그먼트 명령입니다. 파이프는 세로 막대(|) 구분 기호로 표시합니다. 파이프라인 세그먼트 명령은 파이프라인에 나타나는 DCL 명령입니다. 파이프는 파이프라인 세그먼트의 SYS$OUTPUT을 다음 명령의 SYS$INPUT에 연결합니다. 파이프라인의 형식은 다음과 같습니다.
PIPE pipeline-segment-command | pipeline-segment-command [|...]
각 파이프라인 세그먼트 명령은 다음 파이프라인 세그먼트 명령의 SYS$INPUT에 연결된 SYS$OUTPUT이 있는 별개의 하위 프로세스에서 실행됩니다. 이 하위 프로세스들은 병행하여 실행됩니다. 그러나 첫 번째를 제외한 각 파이프라인 세그먼트 명령이 선행 파이프라인 세그먼트 명령의 표준 출력을 표준 입력으로 읽을 정도로 동기화됩니다. 파이프라인은 마지막 파이프라인 세그먼트 명령이 끝날 때 실행을 완료합니다.
파이프라인에 “필터 어플리케이션”을 사용하는 것은 매우 일반적인 일입니다. 필터 어플리케이션은 SYS$INPUT에서 데이터를 받아 특정한 방법으로 변환하여 SYS$OUTPUT에 쓰는 프로그램입니다.
DCL의 어떤 면은 다음 보기처럼 파이프라인 컨텍스트에서 다른 기능을 합니다.
SYS$COMMAND 사용
하위 프로세스의 SYS$COMMAND는 명령 프로시저가 관련되지 않는 경우 일반적으로 SYS$INPUT과 동일합니다. 그러나 파이프라인에서 하위 프로세스의 SYS$COMMAND는 파이프라인 세그먼트 명령의 SYS$INPUT인 선행하는 파이프가 아니라 선행 프로세스의 SYS$COMMAND로 설정됩니다.
파일 액세스 방법
파이프라인 세그먼트 명령은 RMS 순차적 파일 액세스 방법을 사용해서만 파이프에 읽고 쓸 수 있습니다. 특정 OpenVMS 유틸티리는 순차적 액세스가 아닌 방법을 사용하여 입력 및 출력 파일에 액세스할 수 있습니다. 파이프라인에서는 이러한 작업이 지원되지 않으므로 다음 보기처럼 실패하게 됩니다.
$ PIPE CC/NOOBJ/NOLIS TEST.C | SEARCH SYS$INPUT/WIND=(1,1) "%cc-w-"

%SEARCH-F-RFAERR, RMS error using RFA access
-RMS-F-RAC, invalid record access mode
이 보기에서 SEARCH 명령을 위한 /WINDOW 한정자는 관련 파일 액세스 방법을 필요로 합니다.
기호 대체
DCL에서 기호가 변환되는 순서에 주의하십시오. 기호 대체는 명령 처리의 1 단계 동안에 이루어집니다. 기호를 PIPE 명령의 일부로 정의하면 DCL에서는 그 기호가 실제로 정의된 명령을 수행하기 전에 기호를 대체하려고 시도합니다. 기호 대체를 지연하려면 앰퍼샌드(&)를 사용합니다. 자세한 내용은 기호 약어를 참조하십시오.
SYS$PIPE 사용
대부분의 경우 파이프의 입력 사항은 SYS$INPUT에서 데이터를 읽어 가져올 수 있습니다. 그러나 명령 프로시저가 파이프라인 세그먼트 명령으로 호출되면 SYS$INPUT이 그 명령 프로시저 파일로 재지정됩니다. 명령 프로시저 내의 파이프에서 데이터를 가져오려면 논리 SYS$PIPE를 사용할 수 있습니다.
다음 보기는 파이프라인 DCL 어플리케이션인 TEE.COM의 예입니다.
$ ! TEE.COM - command procedure to display/log data flowing through
$ ! a pipeline
$ ! Usage: @TEE log-file
$
$ OPEN/WRITE tee_file 'P1'
$ LOOP:
$ READ/END_OF_FILE=EXIT SYS$PIPE LINE
$ WRITE SYS$OUTPUT LINE ! Send it out to the next stage of the pipeline
$ WRITE tee_file LINE ! Log output to the log file
$ GOTO LOOP
$ EXIT:
$ CLOSE tee_file
$ EXIT
TEE.COM을 사용하려면 다음 PIPE 명령을 입력하십시오.
$ PIPE SHOW SYSTEM | @TEE showsys.log | SEARCH SYS$INPUT LEF
TEE.COM 명령 프로시저는 파이프라인을 통한 데이터 흐름을 기록하는 데 사용됩니다. 이 명령 프로시저는 SYS$INPUT 대신 SYS$PIPE에서 데이터를 읽어들입니다.
이미지 확인
파이프라인에서는 PIPE 명령이 입력되기 전에 SET VERIFY=IMAGE 명령이 실행될 때도 기본적으로 이미지 확인을 사용하지 않습니다. 따라서 파이프라인을 통과해 가는 데이터 레코드가 중복되지 않습니다.
파이프라인에서 이미지 확인을 사용하려면 SET VERIFY=IMAGE 명령을 파이프라인 세그먼트 명령 앞에 두어야 합니다. 다음과 같이 서브셸을 사용할 수 있습니다.
$ PIPE ... | (SET VERIFY=IMAGE ; ...) | ...
서브셸 실행을 위한 PIPE 명령 사용
서브셸은 구분 기호로 구분된 한 개 이상의 명령 순서를 괄호로 묶은 것입니다. 서브셸의 형식은 다음과 같습니다.
PIPE ( command-sequence [separator command-sequence]...)
서브셸의 명령 순서는 하위 프로세스 환경에서 실행됩니다. DCL에서는 다음 명령 순서를 실행하기 전에 서브셸이 종료되기를 기다립니다. 구분 기호( )는 SPAWN/WAIT 명령과 비슷합니다.
PIPE 명령을 이 형식으로 사용할 때는 기호 대체를 주의하여 처리하십시오. 기호를 정의한 후 그 기호에 대한 이후 참조 앞에는 앰퍼샌드(&)를 붙여 기호 대체를 지연합니다. 그렇지 않으면 명령 처리 1 단계 동안 기호 대체가 이루어져 기호 정의를 신뢰할 수 없게 됩니다.
백그라운드 실행을 위한 PIPE 명령 사용
다음 형식을 사용하여 명령 순서를 하위 프로세스 환경에서 실행할 수 있습니다.
PIPE command-sequence [ separator command-sequence]... &
DCL에서 명령 순서가 끝날 때까지 기다리지 않습니다. 일단 백그라운드 하위 프로세스가 만들어지면 제어가 DCL로 다시 전달됩니다.
입/출력 재지정을 위한 PIPE 명령 사용
명령 순서를 사용하여 다음과 같이 명령을 실행하는 동안 SYS$INPUT, SYS$OUTPUT
또는 SYS$ERROR를 파일로 재지정할 수 있습니다.
SYS$INPUT 재지정
PIPE command-sequence < redirected-input-file
SYS$OUTPUT 재지정
PIPE command-sequence > redirected-output-file
SYS$ERROR 재지정
PIPE command-sequence 2> redirected-error-file
파이프라인-세그먼트 명령을 사용하여 SYS$INPUT, SYS$OUTPUT 또는 SYS$ERROR를 지정할 수 있습니다. 그러나 SYS$OUTPUT 재지정은 마지막 파이프라인 세그먼트 명령에 대해서만 허용되며 SYS$INPUT 재지정은 첫 번째 파이프라인 세그먼트 명령에 대해서만 허용됩니다.
PIPE 명령 재지정은 DEFINE 또는 ASSIGN 명령을 사용하여 만든 것과 다릅니다.
차이점은 다음과 같습니다.
재지정은 감독자 모드에서 만들어집니다. 따라서 사용자 모드 어플리케이션과 DCL 명령이 모두 재지정의 영향을 받습니다.
재지정된 환경은 재지정 구문을 지정하는 명령 순서나 파이프라인 세그먼트 명령에만 적용됩니다. 명령 순서나 파이프라인 세그먼트 명령 실행 후 명령 실행을 계속하기 전에 원래 프로세스 입/출력 환경(예: SYS$INPUT, SYS$OUTPUT, SYS$ERROR)이 복원됩니다.
SYS$OUTPUT이 재지정되면 명령 순서가 실제로 SYS$OUTPUT에 쓰거나 쓰지 않거나 항상 재지정된 출력 파일이 만들어집니다. 재지정된 출력 파일과 같은 이름의 파일 버전이 이미 존재하는 경우에는 그 파일의 새 버전이 만들어집니다. DEFINE 또는 ASSIGN 명령을 사용하여 감독자 모드에서 SYS$OUTPUT을 재정의하는 경우에도 마찬가지입니다. 재지정된 파일은 명령 순서가 실행되기 전에 만들어진다는 점에 주의하십시오. 재지정된 파일이 명령 순서에서도 사용되는 경우에는 다음 보기처럼 작업이 실패할 수 있습니다.
$ PIPE SEARCH TRANS.LOG "alpha" > TRANS.LOG

%SEARCH-W-OPENIN, error opening TRANS.LOG;2 as input
-RMS-E-FLK, file currently locked by another user
이 보기에서는 TRANS.LOG 파일의 새 버전이 만들어지고 쓰기 액세스를 위해 열리고 SEARCH 명령은 예상되는 이전 버전 대신 가장 최근 TRANS.LOG 버전에 대해 읽기 액세스를 얻으려고 시도합니다.
SYS$ERROR가 재지정될 때 재지정된 오류 파일은 명령 순서가 실행되는 동안 실제로 SYS$ERROR에 쓰는 경우와 재지정된 오류 파일과 같은 이름의 기존 파일이 없는 경우에만 만들어집니다. 재지정된 오류 파일과 같은 이름의 파일이 이미 존재하는 경우에는 그 파일이 재지정된 오류 파일로 열립니다. 그 다음에는 이 명령 순서에 의해 생성된 오류 출력이 재지정된 오류 파일의 끝에 추가됩니다. DEFINE 또는 ASSIGN 명령을 사용하여 감독자 모드에서 SYS$ERROR를 재정의하는 경우에도 마찬가지입니다.
PIPE 명령 중단
Ctrl/Y를 누르면 PIPE 명령을 중단할 수 있습니다. PIPE 명령이 파이프라인이나 서브셸 명령 순서에서 실행되는 경우에는 명령 순서와 PIPE 명령이 삭제됩니다. 이 경우 중단된 바로 뒤에 입력된 CONTINUE 명령은 PIPE 명령 실행을 재개하지 않을 것입니다.
PIPE 명령이 서브셸이나 파이프라인 명령 순서가 아닌 명령 순서를 실행하는 중이면 명령 순서가 PIPE 명령 동사 없이 DCL 명령으로 입력되었고 Ctrl/Y에 의해 중단된 것처럼 동작합니다. Ctrl/Y 중단에 대한 자세한 내용은 Ctrl/Y 중단 처리를 참조하십시오.
하위 프로세스 성능 향상
PIPE 명령은 실행되는 동안 몇 개의 하위 프로세스를 생성할 수 있습니다. 많은 경우 명령 순서에 의해 호출된 어플리케이션은 프로세스 논리 이름과 기호 이름에 의존하지 않습니다. 이러한 경우에는 프로세스 논리 이름과 기호가 PIPE 명령에 의해 생성된 하위 프로세스에 전달되지 않도록 하는 /NOLOGICAL_NAMES 및 /NOSYMBOLS 한정자를 사용하여 하위 프로세스 생성을 가속화할 수 있습니다.
다음은 PIPE 명령을 사용하는 보기들입니다.
다음 보기는 기호 정의가 포함된 여러 명령을 사용하여 명령 프로시저에서 유용한 도구를 만드는 두 가지 간단한 방법을 보여 줍니다.
$ CD_WORK :== PIPE SAVE_DIR=F$DIRECTORY() ; SET DEFAULT FOO:[WORK]
$ BACK :== SET DEF 'SAVE_DIR'
$
$ CD_WORK ! Switch to working directory
$ :
$ :
$ BACK ! Switch back to home directory
$ GET_RECORD :== PIPE READ/END_OF_FILE=CLEANUP IN RECORD ; -
F$EDIT(RECORD, "COMPRESS, TRIM")
$
$ OPEN IN EMPLOYEE.DAT
$ LOOP:
$ GET_RECORD
$ :
$ :
$ GOTO LOOP
$
$ CLEAN_UP:
$ :
다음 보기는 컴파일 및 링크 작업을 보여 줍니다. 컴파일에서 오류가 발생하지 않으면 객체 파일이 링크되어 실행 가능한 이미지가 생성됩니다. 프로그램 컴파일에서 오류가 발생하면 링크 단계를 건너뜁니다.
$ PIPE cc foo.c && link foo, sys$library:vaxcrtl.olb/lib
다음 보기는 조건 명령 실행을 사용하여 명령 프로시저에서 간단한 오류 처리 제어 흐름을 쉽게 설정하는 방법을 보여 줍니다. COLLECT_DATA 이미지가 실패하면 제어가 CLEAN_UP으로 전달됩니다.
$ PIPE RUN COLLECT_DATA.EXE GOTO CLEAN_UP
$ :
$ :
$ EXIT
$
$ CLEAN_UP:
$ :
$ :
다음 보기에서 PIPE 명령은 백그라운드 프로세스를 만들어 크기가 큰 파일 복사를 처리합니다.
$ PIPE COPY LARGE_FILE.DAT REMOTE"user password"::[DESTINATION]*.* &
다음 보기는 하위 프로세스에서 수행될 서브셸 명령 순서를 설정하는 방법을 보여 줍니다. 결과적으로 기본 디렉토리와 같은 특정 프로세스의 특성을 변경해도 서브셸이 종료된 후 현재 프로세스는 영향을 받지 않습니다. 저장 집합은 하위 디렉토리에 복원되어 FOO 프로그램을 실행하는 데 필요한 데이터를 제공합니다.
$ PIPE (SET DEF [.DATA_DIR] ; BACKUP DATA.SAV/SAV [...]) ; RUN FOO
다음 보기에서는 파이프라인 기능을 사용하여 시스템 상의 모든 휴면 프로세스를 한 명령에서 식별합니다.
$ PIPE SHOW SYSTEM | SEARCH SYS$INPUT HIB
다음 보기에서는 파이프라인 기능을 사용하여 불필요한 중간 파일을 만들지 않고 한 명령에서 테스트를 실행하여 결과를 정렬하고 벤치마크 파일과 비교합니다.
$ PIPE RUN TEST | SORT/SPECIFICATION=TEST.SRT SYS$INPUT SYS$OUTPUT -
| DIFF SYS$INPUT TEST.BENCHMARK
다음 보기는 서브셸을 파이프라인의 파이프 세그먼트 명령으로 지정할 수 있는 한 가지 방법을 보여 줍니다.
$ PIPE ( SET DEF WRK$:[WORK] ; RUN REPORT ) | MAIL SYS$INPUT SMITH
다음 보기는 파이프라인 내의 /PAGE 한정자 사용을 보여 줍니다. 몇 가지 다른 DCL 명령에도 있는 /PAGE 기능은 PIPE 명령과 함께 사용하여 다른 유용한 도구를 만들 수 있습니다.
$ more :== TYPE/PAGE=SAVE SYS$INPUT
$ PIPE ANA/RMS PAGE.TXT | more

Check RMS File Integrity 26-JAN-2002 16:12:00.06 Page 1
SYS$SYSDEVICE:[TEST]PAGE.TXT;2

FILE HEADER

File Spec: SYS$SYSDEVICE:[TEST]PAGE.TXT;2
File ID: (4135,58220,0)
Owner UIC: [PIPE]
Protection: System: RWED, Owner: RWED, Group: RE, World:
Creation Date: 26-NOV-2002 16:08:50.05
Revision Date: 26-NOV-2002 16:09:09.06, Number: 1
Expiration Date: none specified
Backup Date: none posted
Contiguity Options: none
Performance Options: none
Reliability Options: none
Journaling Enabled: none

RMS FILE ATTRIBUTES

RETURN/SPACE=More, PREV/NEXT=Scroll, INS/REM=Pan, SELECT=80/132, Q=Quit


TOC PREV NEXT INDEX