open — 파일 또는 명령 파이프라인 채널 열기

open — 파일 또는 명령 파이프라인 채널 열기

파일을 읽거나 쓰거나, 외부 명령과 파이프라인으로 통신해야 할 때 open 명령이 출발점이에요. 파일·시리얼 포트·명령 파이프라인을 열고, 이후 read·puts·close 같은 명령에서 쓸 채널 식별자(channel identifier)를 돌려줍니다.

출처: Tcl Commands — open

본문

open fileName
open fileName access
open fileName access permissions

이 명령은 파일·시리얼 포트·명령 파이프라인을 열고, 이후 read, puts, close 같은 명령 호출에서 사용할 수 있는 채널 식별자를 돌려줘요. fileName의 첫 문자가 |가 아니면 파일을 열어요. fileNamefilename 매뉴얼에 설명된 규칙을 따라야 해요.

access 인수가 있으면 파일(또는 명령 파이프라인)에 접근하는 방식을 나타내요. 첫 번째 형식에서 access는 다음 값 중 하나를 가질 수 있어요.

r 파일을 읽기 전용으로 열어요. 파일이 이미 존재해야 해요. access를 지정하지 않으면 이 값이 기본값이에요.

r+ 파일을 읽기·쓰기 둘 다로 열어요. 파일이 이미 존재해야 해요.

w 파일을 쓰기 전용으로 열어요. 존재하면 잘라내고, 존재하지 않으면 새 파일을 만들어요.

w+ 파일을 읽기·쓰기로 열어요. 존재하면 잘라내고, 존재하지 않으면 새 파일을 만들어요.

a 파일을 쓰기 전용으로 열어요. 파일이 존재하지 않으면 새 빈 파일을 만들어요. 각 쓰기 전에 파일 포인터를 파일 끝으로 설정해요.

a+ 파일을 읽기·쓰기로 열어요. 파일이 존재하지 않으면 새 빈 파일을 만들어요. 초기 접근 위치를 파일 끝으로 설정해요.

위의 모든 유효한 접근 값에 문자 b를 값의 두 번째 또는 세 번째 문자로 추가할 수 있어요. 그러면 열린 채널이 fconfigure -translation binary 옵션을 쓴 것처럼 설정돼서, 바이너리 데이터의 읽기·쓰기에 적합해져요.

두 번째 형식에서 access는 아래 플래그 중 아무거나의 리스트예요. 대부분 표준 POSIX 의미를 가져요. RDONLY, WRONLY, RDWR 중 하나가 있어야 해요.

RDONLY 파일을 읽기 전용으로 열어요.

WRONLY 파일을 쓰기 전용으로 열어요.

RDWR 파일을 읽기·쓰기 둘 다로 열어요.

APPEND 각 쓰기 전에 파일 포인터를 파일 끝으로 설정해요.

BINARY 열린 채널을 -translation binary 옵션으로 설정해요.

CREAT 파일이 아직 없으면 만들어요(이 플래그가 없으면 파일이 없다는 것은 오류예요).

EXCL CREAT도 지정되면, 파일이 이미 존재할 때 오류를 돌려줘요.

NOCTTY 파일이 터미널 장치이면, 이 플래그는 파일이 프로세스의 제어 터미널이 되는 것을 막아요.

NONBLOCK 파일을 열 때, 그리고 이후 I/O 연산에서 프로세스가 블로킹되는 것을 막아요. 이 플래그의 정확한 동작은 시스템·장치에 따라 달라져요. 사용이 권장되지 않아요(fconfigure 명령으로 파일을 논블로킹 모드로 두는 것이 더 좋아요). 자세한 내용은 open 시스템 호출의 O_NONBLOCK 플래그에 대한 시스템 문서를 참고해요.

TRUNC 파일이 존재하면 길이 0으로 잘라요.

열기의 일부로 새 파일이 만들어지면 permissions(정수)가 프로세스의 파일 모드 생성 마스크와 함께 새 파일의 권한을 설정하는 데 사용돼요. permissions는 기본값 0666이에요.

명령 파이프라인

fileName의 첫 문자가 |이면, 나머지 fileName 문자들은 호출할 명령 파이프라인을 설명하는 인수 목록으로 취급돼요. exec의 인수와 같은 방식이에요. 이 경우 open이 돌려주는 채널 식별자로 명령의 입력 파이프에 쓰거나 출력 파이프에서 읽을 수 있어요. 어떤 쪽인지는 access 값에 따라 달라져요.

쓰기 전용 접근(예: access"w")을 쓰면 파이프라인의 표준 출력은 명령이 덮어쓰지 않으면 현재 표준 출력으로 향해요. 읽기 전용 접근(예: access"r")을 쓰면 파이프라인의 표준 입력은 명령이 덮어쓰지 않으면 현재 표준 입력에서 가져와요. 생성된 프로세스의 id는 open이 돌려준 채널 id를 인수로 pid 명령으로 접근할 수 있어요.

명령 파이프라인에서 실행된 명령(또는 그중 하나)이 오류를 반환하면(exec의 정의 기준), 채널에 close가 호출될 때 Tcl 오류가 생성돼요. 단, 파이프라인이 논블로킹 모드이면 종료 상태가 반환되지 않아요(-blocking 0으로 조용히 닫힘).

파이프라인과 함께 fileevent 명령을 사용하면 백그라운드에서 명령을 실행하는 동안 다른 처리를 동시에 할 수 있어서 유용해요.

시리얼 통신

fileName이 시리얼 포트를 가리키면, 지정된 시리얼 포트가 플랫폼에 따라 열리고 초기화돼요. 시리얼 포트를 여는 데 사용할 수 있는 fileName의 허용 값은 "이식성 이슈" 섹션에 설명돼 있어요.

fconfigure 명령으로 시리얼 포트에 특화된 추가 구성 옵션(지원되는 곳)을 조회·설정할 수 있어요:

-mode baud,parity,data,stop 이 시리얼 포트의 baud rate, parity, 데이터 비트 수, 스톱 비트 수를 콤마로 구분한 4개 값의 집합이에요. baud rate는 연결 속도를 지정하는 단순 정수예요. Parity는 n, o, e, m, s 중 하나의 문자로, 각각 "none", "odd", "even", "mark", "space" 패리티 옵션을 뜻해요. data는 데이터 비트 수로 5에서 8 사이의 정수, stop은 스톱 비트 수로 1 또는 2의 정수여야 해요.

-handshake type (Windows와 Unix) 자동 핸드셰이크 제어를 설정하는 데 쓰여요. 모든 핸드셰이크 유형이 운영체제에서 지원되지는 않을 수 있다는 점을 기억하세요. type 매개변수는 대소문자를 구분하지 않아요. typenone이면 어떤 핸드셰이크든 꺼져요. rtscts는 하드웨어 핸드셰이크를 활성화해요(하드웨어 핸드셰이크 신호는 아래 설명). 소프트웨어 핸드셰이크 xonxoff에 대해선 핸드셰이크 문자를 -xchar로 재정의할 수 있어요. 추가 하드웨어 핸드셰이크 dtrdsr은 Windows에서만 사용할 수 있어요. 기본 핸드셰이크 구성은 없고, 초기 값은 운영체제 설정에 따라 달라져요. -handshake 옵션은 조회할 수 없어요.

-queue (Windows와 Unix) -queue 옵션은 조회만 할 수 있어요. 각각 입력 및 출력 큐의 현재 바이트 수를 나타내는 두 정수의 리스트를 돌려줘요.

-timeout msec (Windows와 Unix) 이 옵션은 블로킹 읽기 연산의 타임아웃을 설정하는 데 쓰여요. 두 바이트 수신 사이의 최대 간격을 밀리초로 지정해요. Unix 시스템의 세분성은 100밀리초예요. -timeout 옵션은 쓰기 연산이나 논블로킹 읽기에는 영향을 주지 않아요. 이 옵션은 조회할 수 없어요.

-ttycontrol {signal boolean signal boolean ...} (Windows와 Unix) 이 옵션은 핸드셰이크 출력 라인(아래 참고)을 영구적으로 설정하거나 시리얼 라인으로 BREAK를 보내는 데 쓰여요. 신호 이름은 대소문자를 구분하지 않아요. {RTS 1 DTR 0}은 RTS 출력을 높게, DTR 출력을 낮게 설정해요. BREAK 조건(아래 참고)은 {BREAK 1}{BREAK 0}으로 각각 활성·비활성화돼요. 활성 하드웨어 핸드셰이크 rtscts(또는 dtrdsr)에서 RTS(또는 DTR) 신호를 바꾸는 것은 좋지 않아요. 결과를 예측할 수 없어요. -ttycontrol 옵션은 조회할 수 없어요.

-ttystatus (Windows와 Unix) -ttystatus 옵션은 조회만 할 수 있어요. 현재 모뎀 상태와 핸드셰이크 입력 신호(아래 참고)를 돌려줘요. 결과는 고정 순서의 signal,value 쌍 목록이에요. 예: {CTS 1 DSR 0 RING 1 DCD 0}. 신호 이름은 대문자로 반환돼요.

-xchar {xonChar xoffChar} (Windows와 Unix) 이 옵션은 소프트웨어 핸드셰이크 문자를 조회하거나 변경하는 데 쓰여요. 보통 운영체제 기본값은 ASCII 표준 XON·XOFF 문자를 나타내는 DC1(0x11)과 DC3(0x13)이어야 해요.

-pollinterval msec (Windows만) 이 옵션은 fileevent 폴링 사이의 최대 시간을 설정하는 데 쓰여요. 이것은 Tcl 인터프리터 전체에서 이벤트를 확인하는 사이의 시간 간격에 영향을 줘요(가장 작은 값이 항상 이겨요). 이 옵션은 10msec(기본값)보다 자주 또는 드물게 시리얼 포트를 폴링하고 싶을 때만 사용해요.

-sysbuffer inSize / -sysbuffer {inSize outSize} (Windows만) 이 옵션은 시리얼 채널용 Windows 시스템 버퍼 크기를 바꾸는 데 쓰여요. 특히 더 높은 통신 속도에서 기본 입력 버퍼 크기 4096바이트는 지연 시스템에서 오버런(overrun)할 수 있어요. 첫 번째 형식은 입력 버퍼 크기를 지정하고, 두 번째 형식은 입력·출력 버퍼를 모두 정의해요.

-lasterror (Windows만) 이 옵션은 조회 전용이에요. 시리얼 통신 오류가 발생하면 readputs가 일반 Tcl 파일 I/O 오류를 돌려줘요. fconfigure -lasterror를 호출해 오류 세부 정보 목록을 얻을 수 있어요. 다양한 오류 코드에 대한 설명은 아래를 참고해요.

시리얼 포트 신호

RS-232는 시리얼 통신에 가장 흔히 쓰이는 표준 전기 인터페이스예요. 음전압(-3V..-12V)은 mark(on=1) 비트, 양전압(+3..+12V)은 space(off=0) 비트를 정의해요(RS-232C). 다음 신호들이 들어오고 나가는 데이터, 상태 라인, 핸드셰이킹에 지정돼 있어요. 여기서는 컴퓨터를 workstation, 외부 장치를 modem이라고 부를게요. 일부 신호 이름(DCD, RI)이 모뎀에서 왔기 때문이에요. 물론 외부 장치가 이 신호 라인을 다른 목적으로 사용할 수도 있어요.

TXD(출력) — Transmitted Data: 나가는 시리얼 데이터. RXD(입력) — Received Data: 들어오는 시리얼 데이터. RTS(출력) — Request To Send: 이 하드웨어 핸드셰이크 라인은 워크스테이션이 데이터를 받을 준비가 되었음을 모뎀에 알려요. 워크스테이션은 입력 버퍼가 가득 찼음을 나타내기 위해 이 신호를 자동으로 재설정할 수 있어요. CTS(입력) — Clear To Send: RTS의 보완. 모뎀이 데이터를 받을 준비가 되었음을 나타내요. DTR(출력) — Data Terminal Ready: 이 신호는 워크스테이션이 링크를 설정할 준비가 되었음을 모뎀에 알려요. DTR은 시리얼 포트가 열릴 때마다 자주 자동으로 활성화돼요. DSR(입력) — Data Set Ready: DTR의 보완. 모뎀이 링크를 설정할 준비가 되었음을 워크스테이션에 알려요. DCD(입력) — Data Carrier Detect: 모뎀이 "Carrier" 신호를 감지하면 이 라인이 활성화돼요. RI(입력) — Ring Indicator: 모뎀이 들어오는 호출을 감지하면 활성화돼요. BREAK — BREAK 조건은 하드웨어 신호 라인이 아니라, 보통 250에서 500밀리초 동안 TXD나 RXD 라인의 논리 0이에요. 보통 수신·송신 데이터 신호는 다음 문자가 전송될 때까지 mark(on=1) 전압을 유지해요. BREAK는 통신 라인을 재설정하거나 통신 하드웨어의 동작 모드를 바꾸는 데 때때로 사용돼요.

오류 코드 (Windows만)

시리얼 읽기 연산이나 백그라운드 이벤트 폴링 중 많은 다른 오류가 발생할 수 있어요. 외부 장치가 꺼져 있거나, 데이터 라인이 시끄럽거나, 시스템 버퍼가 오버런하거나, 모드 설정이 잘못됐을 수 있어요. 그래서 안정적인 소프트웨어는 항상 시리얼 읽기 연산을 잡아야 해요. 오류가 나면 Tcl이 일반 파일 I/O 오류를 돌려줘요. 그러면 fconfigure -lasterror로 문제를 찾는 데 도움을 받을 수 있어요. 다음 오류 코드들이 반환될 수 있어요.

RXOVER — Windows 입력 버퍼 오버런. 스크립트가 읽는 것보다 데이터가 더 빨리 오거나 시스템이 과부하된 상태예요. fconfigure -sysbuffer로 임시 병목을 피하거나 스크립트를 더 빠르게 만들어요. TXFULL — Windows 출력 버퍼 오버런. RXOVER의 보완. Tcl이 출력 버퍼 상태를 관리하므로 실제로는 거의 발생하지 않아야 해요. OVERRUN — UART 버퍼 오버런(하드웨어), 데이터 손실 동반. 시스템 드라이버가 받는 것보다 데이터가 더 빨리 와요. 고급 시리얼 포트 설정을 확인해 FIFO(16550) 버퍼를 활성화하거나 더 낮은(1) 인터럽트 임계값을 설정해요. RXPARITY — UART가 패리티 오류를 감지했어요. fconfigure -mode의 잘못된 패리티 설정이나 시끄러운 데이터 라인(RXD)이 이 오류를 일으킬 수 있어요. FRAME — UART가 스톱 비트 오류를 감지했어요. fconfigure -mode의 잘못된 모드 설정이나 시끄러운 데이터 라인(RXD)이 이 오류를 일으킬 수 있어요. BREAK — UART가 BREAK 조건을 감지했어요(위 참고).

이식성 이슈

Windows — 시리얼 포트를 여는 유효한 fileName 값은 comX 형태이고, X는 보통 1에서 9 사이의 숫자예요. comX: 형식도 옛 방식으로 허용돼요. 이 표기는 시리얼 포트 1에서 9까지만 작동해요. 존재하지 않거나 9보다 큰 숫자의 시리얼 포트를 열려고 하면 실패해요. 시리얼 포트를 여는 대체 형태는 //./comX 파일명을 쓰는 것이고, X는 시리얼 포트에 해당하는 어떤 숫자든 돼요.

Tcl을 대화형으로 실행할 때, 실제 콘솔이 있으면 콘솔과 표준 입력·출력을 쓰는 명령 파이프라인 사이에 이상한 상호작용이 있을 수 있어요. 파이프라인이 읽기용으로 열리면 콘솔에 입력한 일부 줄이 파이프라인으로, 일부는 Tcl 평가자로 보내져요. 파이프라인이 쓰기용으로 열리면 파이프가 닫힐 때까지 콘솔에 입력한 키 입력이 보이지 않아요. 이 문제들은 Tcl과 자식 애플리케이션이 동시에 콘솔을 놓고 경쟁하기 때문에만 생겨요. 파이프라인이 스크립트에서 시작되어 Tcl이 콘솔에 접근하지 않거나, 파이프라인이 표준 입력·출력을 쓰지 않고 파일로부터/로 리다이렉트된다면 위 문제들이 생기지 않아요.

"a" 모드나 APPEND 플래그를 설정해 연 파일은 각 쓰기 직전에 seek해서 구현돼요. 이것은 원자적 연산이 아니며, POSIX 플랫폼에 존재하는 엄격한 추가(append) 보장을 가지지 않아요.

Unix — 시리얼 포트를 여는 유효한 fileName 값은 보통 /dev/ttyX 형태이고, X는 a나 b지만, 시리얼 포트에 매핑되는 어떤 의사 파일 이름도 쓸 수 있어요. 고급 구성 옵션은 Tcl이 POSIX 시리얼 인터페이스를 쓰도록 빌드된 경우에만 시리얼 포트에서 지원돼요.

Tcl을 대화형으로 실행할 때, 콘솔이 있으면 콘솔과 표준 입력을 쓰는 명령 파이프라인 사이에 이상한 상호작용이 있을 수 있어요. 파이프라인이 읽기용으로 열리면 콘솔에 입력한 일부 줄이 파이프라인으로, 일부는 Tcl 평가자로 보내져요. 이 문제는 Tcl과 자식 애플리케이션이 동시에 콘솔을 놓고 경쟁하기 때문에만 생겨요. 파이프라인이 스크립트에서 시작되어 Tcl이 콘솔에 접근하지 않거나, 파이프라인이 표준 입력을 쓰지 않고 파일로부터 리다이렉트된다면 위 문제가 생기지 않아요.

명령 파이프라인에 국한되지 않는 다양한 플랫폼에서 애플리케이션을 실행하는 것에 대한 추가 정보는 exec 명령의 "이식성 이슈" 섹션을 참고해요.

예제

파일을 쓰기용으로 열되 존재하면 오류를 내며 강제 생성해요.

set myNewFile [open filename.txt {WRONLY CREAT EXCL}]

로그 파일로 쓰기 위해 파일을 열어요.

set myLogFile [open filename.log "a"]
fconfigure $myLogFile -buffering line

명령 파이프라인을 열고 오류를 잡아요.

set fl [open "| ls this_file_does_not_exist"]
set data [read $fl]
if {[catch {close $fl} err]} {
    puts "ls command failed: $err"
}

명령 파이프라인을 열고 바이너리 데이터를 읽어요. 공백이 있을 수 있는 인수의 중요한 가장자리 경우를 처리하는 |[list 형태의 특이한 표기에 주목하세요.

set fl [open |[list create_image_data $input] "rb"]
set binData [read $fl]
close $fl

더 알아보기

  • file, close, filename, fconfigure, gets, read, puts — 파일·채널 처리
  • exec, pid — 외부 프로그램 실행·프로세스 ID
  • fopen — C 표준 입출력