Programming/TclTk

TCL UNIX에서 작업하기

Hunveloper 2022. 9. 6. 08:42
728x90

UNIX에서 작업하기

  • 글의 기본은 UNIX를 기초로 하지만, DOS나 Macintosh 등에서도 TCL 해석기가 있기에 사용 가능

exec 명령으로 UNIX 프로그램 수행

  • exec 명령은 TCL 스크립트에서 UNIX 명령을 수행
set d [exec date]
  • 수행 결과는 표준 출력으로 출력된 결과
  • 만약 수행한 프로그램이 표준 오류 출력으로 결과를 찍거나 상태 코드 값이 0이 아닐 경우는 에러
  • exec 명령은 I/O redirection과 pipeline 구문을 완벽히 지원
  • exec 명령에서 사용할 수 있는 여러 문법
    • keepnewline : 결과값의 마지막에 있는 newline 문자를 없애지 않음
    • | : pipeline
    • |& : 표준 에러 출력으로도 파이프라인 수행
    • < fileName : fileName 파일로부터 입력
    • <@ fileId : fileId의 id를 가지는 I/O 스트림으로부터 입력
    • << value : 주어진 값으로부터 입력
    • > fileName : fileName 파일에 결과를 저장
    • 2> fileName : fileName 파일에 표준 에러 출력 결과를 저장
    • >& fileName : 표준 출력과 표준 에러 출력 결과를 모두 fileName 파일에 저장
    • >>fileName : fileName 파일에 표준 출력 결과를 덧붙임 (append)
    • 2>> fileName : fileName 파일에 표준 에러 출력 결과를 덧붙임
    • >>& fileName : fileName 파일에 표준 출력과 표준 에러 출력 결과를 덧붙임
    • >@ fileId : fileId id를 가지는 I/O 스트림에 표준 출력 결과를 저장
    • 2>@ fileId : fileId id를 가지는 I/O 스트림에 표준 에러 출력 결과를 저장
    • >&@ fileId : fileId id를 가지는 I/O 스트림에 표준 출력과 표준 에러 출력 결과를 저장
    • & : 백그라운드로 수행. 결과값은 프로세스 ID.
  • TCL 쉘 프로그램은 기본적으로 TCL 명령이 아닌 명령을 수행할 때 UNIX로 수행
  • 이 기능을 종료하기 위해서 아래의 명령을 사용
set auto_noexec anything

파일 시스템

  • file 명령은 파일의 상태를 알 수 있는 여러 명령을 제공
  • 다음은 file 명령의 여러 형태를 나열한 것
    • file atime name : 가장 최근에 파일에 접근한 시간을 10진수의 스트링으로 반환
    • file dirname name : name 파일이 위치하는 디렉토리 이름을 반환
    • file executable name : 실행 가능한 파일인 경우 1, 그렇지 않은 경우 0 반환
    • file exists name : 파일이 존재하는 경우 1, 그렇지 않은 경우 0 반환
    • file isdirectory name : name 파일이 디렉토리인 경우 1, 그렇지 않은 경우 0 반환
    • file isfile name : name 파일이 디렉토리, 심볼릭 링크, 장치가 아닌 순수 파일인 경우 1, 그렇지 않으면 0 반환
    • file mtime name : 파일의 최근 수정 시간을 반환
    • file owned name : 현재 사용자가 파일의 소유자이면 1, 그렇지 않으면 0 반환
    • file readable name : 파일의 내용 읽기가 허가되어 있으면 1, 그렇지 않으면 0을 반환
    • file readlink name : 심볼릭 링크 name의 내용을 반환
    • file root name : 확장자를 제외한 부분을 반환
    • file extension name : 확장자 부분만을 반환
    • file size name : 파일의 크기를 바이트 단위로 계산해 반환
    • file stat name var : 파일의 상태를 var 배열에 삽입. var 배열에 정의되는 원소들은 atime, ctime, dev, gid, ino, mode, mtime, nlink, size, type, uid임
    • file tail name : 파일의 경로를 제외한 파일 이름 부분만 반환
    • file type name : 파일의 형태를 반환. 파일의 형태는 file, directorhy, characterSpecial, blockSpecial, fifo, link, socket 중의 하나
    • file writable name : 파일 쓰기 허가가 되어 있으면 1, 그렇지 않으면 0을 반환
  • 다음 예제는 두 파일의 수정 시간을 비교하기 위해 file mtime 명령을 사용
proc newer { file1 file2 } {
    if ![file exists $file2] {
        return 1
    } else {
        expr [file mtime $file] > [file mtime $file2]
    }
}
  • makedir 예제는 새로운 디렉토리를 생성할 필요가 있는지 검사하기 위해 file 명령을 사용
  • makedir은 자신을 재귀적으로 호출
proc makedir { pathname } {
    if {[file isdirectory $pathname]} {
        return $pathname
    } elseif {[file exists $pathname]} {
        error "Non-directory $pathname already exists."
    } else {
        makedir [file dirname $pathname]
        exec mkdir $pathname
        return $$pathname
    }
}
  • 가장 일반적인 file의 옵션은 stat와 lstat, 세 번째 파라미터로 상태 정보를 받을 배열 변수를 가짐
  • fileeq는 두 파일이 똑같은 file을 가리키는지를 찾음
proc fileeq { path 1 path2 } {
    file stat $path1 stat1
    file stat $path2 stat2
    expr [$stat1(ino) == $stat2(ino) && \
     $stat1(dev) == $stat2(dev)]
}

입출력 명령

  • 입출력을 위한 명령
    • open what ?access? ?permissions? : 파일이나 파이프라인에 대한 스트림 ID를 리턴
    • puts ?-nonewline? ?stream? string : 스트링을 출력
    • gets stream ?varname? : 한 줄을 읽음
    • read stream ?numBytes? : numBytes 만큼의 바이트를 읽음
    • read -nonewline stream : 스트림으로부터 모든 데이터를 읽고 마지막의 newline 제거
    • tell stream : 현재 검색 중인 위치 리턴
    • seek stream offset ?origin? : 검색 위치를 offset으로 설정. origin은 start, current, end 중 하나
    • eof stream : end-of-file 상태를 질의
    • flush stream : 스트림의 버퍼 쓰기
    • close stream : I/O 스트림을 닫기

파일 열기

  • open 명령은 입출력을 위해 파일을 연다
  • open 명령의 리턴값은 I/O 스트림의 ID이다
  • open의 결과를 저장해 두었다가 stdout이나 stdin, stderr을 사용한 부분에 대신 사용하면 됨
  • open 명령의 기본적인 문법
open what ?access? ?permissions?
  • what 파라미터는 파일이나 파이프라인의 이름
  • access 파라미터는 짧은 문자의 나열로 쓸 수도 있고 POSIX 접근 flag 형태로 쓸 수도 있다.
    • r : 존재하는 파일을 읽을 수 있도록 열기
    • r+ : 존재하는 파일에 읽기와 쓰기를 함
    • w : 존재하는 파일인 경우는 덮어 쓰고 존재하지 않으면 쓰기를 위해 생성함
    • w+ : 존재하는 파일인 경우는 읽고 덮어 쓰고 존재하지 않으면 읽기와 쓰기를 위해 생성
    • a : 존재하는 파일을 쓰기를 위해 열며 쓴 데이터는 뒤에 덧붙여 쓴다
    • a+ : 존재하는 파일을 읽기와 쓰기를 위해 열며 쓴 데이터는 뒤에 덧붙여 쓴다
  • access 파라미터를 POSIX 플래그 형태로 쓰는 경우
    • RDONLY : 읽기전용
    • WRONLY : 쓰기전용
    • RDWR : 읽기와 쓰기
    • APPEND : 파일에 덧붙임
    • CREAT : 파일이 존재하지 않으면 새 파일을 생성
    • EXCL : CREAT와 같이 쓸 때, 파일이 이미 존재하면 에러를 리턴
    • NOCTTY: 터미널 장치가 컨트롤 터미널이 되는 것을 막음
    • NONBLOCK: 파일을 여는 중에 블록 되지 않음
    • TRUNC: 파일이 존재하면 끝을 자름
  • access 파라미터는 기본적으로 read 값을 가짐
  • permission은 파일 생성시 가지는 접근허가 비트, default 0666이며 chmod로 조정가능
  • POSIX 형태의 파라미터를 사용해 파일을 여는 예
set filed [open /tmp/bar {RDWR CREAT}]
  • 파일을 열 때에는 에러 발생 유무를 확인해야 함
  • catch를 사용해 파일을 열 때에 발생한 오류를 확인
if [catch {open /tmp/data r} fileId] {
    puts stderr "Cannot open /tmp/data : $fileId"
} else {
    #read and process the file, then...
    close $fileId
}
  • catch는 에어가 발생시 1, 그렇지 않으면 0을 리턴
  • catch의 두 번째 인자는 결과값을 받을 변수의 이름
  • 파이프라인 문자인 ‘|’를 첫 번째 인자로 사용해 프로세스 파이프라인을 열 수 있음
  • 다음 예제는 UNIX의 sort 프로그램을 사용해 password 파일을 sort후 split 명령을 사용해 결과라인을 리스트 원소로 변환
set input [open "\sort /etc/passwd" r]
set contents [split [read $input] \n]
close $input
  • r+ 접근 모드를 사용하면 파일에 대한 읽기와 쓰기가 모두 가능하게 열 수 있음
  • 파이프라인을 사용할 때에는 버퍼에 유의해야 함
  • puts 명령이 수행된 후라도 버퍼에는 아직 데이터가 남아 있을 수 있음
  • flush 명령을 사용하면 버퍼에 남아있는 데이터를 모두 출력

파일 읽기와 쓰기

  • UNIX의 표준 I/O 스트림은 항상 열려 있음
  • 기본적으로 열려 있는 스트림의 이름은 stdin, stdout, stderr
  • 다른 스트림은 open 명령을 사용해 연다
  • puts 명령은 출력 스트림에 스트링과 newline 문자를 출력
  • -nonewline 옵션을 사용하면 마지막에 newline 문자를 출력하지 않음
puts -nonewline "Enter value : "
set answer [gets stdin]
  • gets 명령은 한 줄의 입력을 받음
  • gets 명령은 두 가지 형태로 사용가능
  • gets의 첫 번째 형태는 위의 예제처럼 I/O 스트림으로부터 한 줄을 읽어 그 값을 반환
  • gets는 마지막의 newline 문자를 없애 주며 파일의 끝에 도달한 경우는 빈 스트링을 반환
  • 빈 줄과 파일의 끝을 구분하기 위해서는 eof 명령을 사용해야 함
  • gets 명령에 두 번째 인자를 주게 되면 결과가 두 번째 인자에 쓰여진 변수에 들어가게 되며 리턴값은 스트링의 길이가 됨
  • 파일의 끝에 다다른 경우는 -1을 반환
  • 다음 예제는 파일의 처음부터 끝까지 읽는 루프의 예
while {[gets $stream line] >= -} {
    #Process line
}
close $stream
  • read 명령은 스트림에서 데이터를 블록 단위로 읽음
  • read 명령도 두 형태로 사용 가능
  • numBytes 파라미터를 주지 않으며 파일 전체의 내용을 반환
  • -nonewline 옵션을 주면 마지막 newline 문자가 지워짐
  • numBytes 파라미터를 주면 numBytes 만큼의 바이트를 읽음
  • numBytes 파라미터와 -nonewline 옵션은 함께 사용할 수 없다
  • 다음 예제는 read 명령을 사용해 파일의 내용을 읽는 예제
foreach line [split [read $stream] \n] {
    #Process line
}
close $stream
  • 일반적인 크기의 파일에서 gets를 사용하는 것보다 read를 사용하는 것이 더 빠름
  • read는 파일 전체의 내용을 일고 split 명령이 read를 줄 단위로 나눔
  • seek와 tell 명령을 사용하면 I/O 스트림의 랜덤한 위치를 접근가능
  • 각 스트림은 seek offset이라고 불리는 스트림에서의 위치를 유지함
  • 파일에서 읽거나 쓰면 seek offset에서 읽거나 쓴 바이트양이 증가
  • tell 명령은 현재의 seek offset 값을 반환
  • seek 명령은 seek offset 값을 설정
  • close 명령은 I/O 스트림에 연결된 시스템 자원을 모두 해제하므로 중요한 명령
  • 파일을 닫지 않으면 프로세스가 끝날 때 자동으로 닫힘

현재 디렉토리 cd와 pwd

  • 모든 UNIX 프로세스는 파일을 찾을 때 기본 위치로 삼는 현재 디렉토리라는 것을 가지고 있음
  • pwd 명령은 현재 디렉토리의 위치를 반환
  • cd 명령은 현재 디렉토리를 변경

glob를 사용해 파일 이름 찾기

  • glob 명령은 패턴을 이용해 파일 이름을 찾음
glob ?flags? pattern ?pattern?
  • 패턴 파라미터의 문법은 string match 명령의 파라미터와 유사
      • : 0개 이상의 문자와 대응
    • ? : 하나의 문자와 대응
    • [abc] : abc 문자 집합과 대응
    • {a,b,c} : a,b,c 중의 하나와 대응
    • 기타 다른 문자는 같은 문자와 대응
    • nocomplain 옵션을 사용하면 일치하는 파일이 없는 경우 빈 스트링을 반환
    • nocomplain 옵션을 사용하지 않으면 일치하는 파일이 없는 경우 에러를 발생
  • FindFile 프로시져는 파일 시스템의 하위 디렉토리를 순차적으로 검색해 원하는 파일을 탐색
proc FindFile {startDir namePat} {
    set pwd [pwd]
    if [catch {cd $startDir} err] {
        puts stderr $err
        return
    }
    foreach match [glob -nocomplain -- $namePat] {
        puts stdout $startDir/$match
    }
    foreach file [glob -nocomplain *] {
        if [file isdirectory $file] {
            FindFile $startDir/$file $namePat
        }
    }
    cd $pwd
}

exit와 pid 명령

  • exit 명령은 스크립트를 종료
  • 스크립트를 수행하던 모든 UNIX 프로세스도 종료
  • exit 명령은 정수 인자를 주면 그 인자가 프로세스의 종료 상태가 됨
  • pid 명령은 현재 프로세스의 프로세스 ID를 반환
  • 이 값은 수행할 때마다 변하기에 난수 발생기 seed의 값으로 활용 가능

환경 변수

  • 환경 변수는 Unix 프로세스와 연결된 스트링 값을 가지는 변수들
  • 프로세스의 환경 변수는 env 배열을 사용해 접근 가능
  • 환경 변수의 이름은 배열의 인덱스가 되면 그 값이 환경 변수의 값과 같게 됨
  • env 배열 값을 바꾸면 그 변경된 값은 환경 변수에도 반영됨
  • 환경 변수는 자식 프로세스에게 상속
  • 다음 프로그램은 환경 변수의 값을 화면에 출력
proc printenv { args } {
    global env
    set maxl 0
    if {[llength $args] == 0} {
        set args [lsort [array names env]]
    }
    foreach x $args {
        if {[string length $x] > $maxl} {
            set maxl [string length $x]
        }
    }
    incr maxl 2
    foreach x $args {
        puts stdout [format "%*s = %s" $maxl $x $env($x)]
    }
}
printenv USER SHELL TERM
728x90
728x90