Linux에서 Go를 스크립트 언어로 사용

12427 단어 golinuxopensource
제가 Cloudflare Blog 에 올린 댓글입니다.
Cloudflare에서 Go를 좋아합니다.우리는 많은 in-house software projectsbigger pipeline systems 부분에서 그것을 사용한다.그러나 Go를 다음 단계로 올리고 가장 좋아하는 운영체제인 Linux의 스크립트 언어로 사용할 수 있습니까?

gopher image CC BY 3.0 Renee French
Tux image CC0 BY OpenClipart-Vectors

Go를 스크립트 언어로 고려하는 이유


간단하게 대답: 왜 안 해요?Go는 상대적으로 배우기 쉽고 지루하지 않으며 처음부터 모든 코드를 작성하지 않도록 커다란 라이브러리 생태계를 가지고 있다.다음과 같은 몇 가지 잠재적 이점을 얻을 수 있습니다.
  • Go 프로젝트의 Go 기반 구축 시스템: go build 명령은 주로 소형 자체 포함 프로젝트에 적용된다.더 복잡한 프로젝트는 일반적으로 시스템/스크립트 집합을 구축한다.왜 이 각본들도 바둑에 쓰지 않습니까?
  • 간편한 비특권 패키지 관리 시작: 스크립트에서 제3자 라이브러리를 사용하려면 간단하게 go get 사용할 수 있습니다.코드가 GOPATH에 설치되기 때문에 제3자 라이브러리를 얻으려면 시스템의 관리 권한이 필요하지 않습니다(다른 스크립트 언어와 다름).이것은 대형 기업 환경에서 특히 유용하다.
  • 프로젝트 초기 단계의 빠른 코드 원형: 코드의 첫 번째 교체를 작성할 때, 대량의 편집을 해야 하고, 심지어는 그것을 컴파일해야 하며, "편집->구축->검사"순환에서 대량의 키를 낭비해야 합니다.반대로'구축'부분을 건너뛰고 원본 파일을 실행할 수 있습니다.
  • 강력한 스크립트 언어: 스크립트 중간에 작은 오타를 치면 대부분의 스크립트가 이 점을 실행하고 오타 자체에 실패한다.이것은 시스템을 일치하지 않는 상태로 만들 수 있다.강한 유형의 언어는 컴파일할 때 많은 맞춤법 오류를 포착할 수 있기 때문에 오류 스크립트는 우선 실행되지 않습니다.
  • Go 스크립트의 현재 상태


    언뜻 보기에는 유닉스의 스크립트 지원shebang lines 때문에 Go 스크립트는 쉽게 실현될 것 같다.shebang 줄은 스크립트의 첫 번째 줄로 #! 시작하여 스크립트를 실행하는 데 사용할 스크립트 해석기(예를 들어 #!/bin/bash 또는 #!/usr/bin/env python를 지정하기 때문에 어떤 프로그래밍 언어를 사용하든지 시스템은 스크립트를 실행하는 방법을 정확하게 알고 있다.Go는 .go 명령을 사용하여 go run 파일에 유사한 해석기를 호출하는 것을 지원하기 때문에 #!/usr/bin/env go run 파일에 적당한shebang 줄을 추가하기만 하면 됩니다. 예를 들어 .go 실행 가능한 위치를 설정하면 시작할 수 있습니다.
    그러나 직접 사용go run에 문제가 있다.This great post 주변의 모든 문제와 잠재적인 해결 방법에 대해 상세히 설명했지만 요점은 다음과 같습니다.
  • go run 스크립트 오류 코드를 운영체제로 정확하게 되돌릴 수 없습니다. 이것은 스크립트에 있어 매우 중요합니다. 오류 코드는 여러 스크립트가 상호작용하고 운영체제 환경에서 가장 흔히 볼 수 있는 방식 중 하나이기 때문입니다.
  • 유효한 go run 파일에 shebang 줄이 있을 수 없습니다. Go는 .go로 시작하는 줄을 어떻게 처리하는지 모르기 때문입니다.다른 스크립트 언어는 이 문제가 없습니다. 대부분의 스크립트 언어 # 는 주석을 지정하는 방법이기 때문에 최종 해석기는 shebang 줄만 무시합니다. 그러나 Go 주석은 호출할 때 #// 로 시작하면 다음과 같은 오류만 발생합니다.
  • package main:
    helloscript.go:1:1: illegal character U+0023 '#'
    
    The post는 사용자 정의 패키지 프로그램gorun을 해석기로 사용하는 등 상술한 문제의 몇 가지 해결 방법을 설명했지만 이상적인 해결 방안을 제공하지 못했다.다음을 수행할 수 있습니다.
  • go run으로 시작하는 비표준shebang선을 사용해야 합니다.기술적으로 말하자면 이것은 심지어shebang행이 아니라 //셸이 실행 가능한 텍스트 파일을 처리하는 방식이기 때문에 이 해결 방안은 bash특정한 것이다.또한 bash의 특정 행위로 인해 이 선은 상당히 복잡하고 뚜렷하지 않다(예 original post.
  • shebang줄에서 사용자 정의 패키지 프로그램gorun을 사용해야 합니다. 이 프로그램은 잘 실행되지만 go run 파일이 생성됩니다. .go 문자가 불법이기 때문에 표준go build 명령을 사용할 수 없습니다.
  • Linux에서 파일을 실행하는 방법


    그래, 보아하니shebang 방법은 우리에게 전면적인 해결 방안을 제공하지 않은 것 같다.또 우리가 쓸 수 있는 것이 있습니까?우선 Linux 커널이 어떻게 바이너리 파일을 실행하는지 자세히 봅시다.바이너리/스크립트 (또는 실행 가능한 비트셋이 있는 파일) 를 실행하려고 시도할 때, 셸은 문제가 있는 바이너리 파일의 파일 시스템 경로, 명령줄 파라미터, 현재 정의된 환경 변수만 리눅스 # system call 를 사용합니다.그리고 커널은 파일을 정확하게 해석하고 파일의 코드를 사용하여 새 프로세스를 만듭니다.대부분의 사람들은 Linux가 실행 파일로 사용됨 ELF binary format 을 알고 있습니다.
    그러나 Linux 커널 개발의 핵심 원칙 중 하나는 모든 하위 시스템 (커널의 일부) 의 공급업체/형식 잠금을 피하는 것이다.따라서 Linux는 내부 핵이 모든 바이너리 형식을 지원할 수 있도록 하는 삽입 가능 시스템을 실현했다. 당신이 해야 할 일은 올바른 모듈을 작성하는 것이다. 이 모듈은 당신이 선택한 형식을 해석할 수 있다.만약 네가 내부 원본 코드를 자세히 보면, 리눅스가 기존의 2진 형식을 더 많이 지원하는 것을 발견할 수 있을 것이다.예를 들어 최근의 execve Linux 커널we can see의 경우 최소 7개의 바이너리 형식을 지원합니다(다양한 바이너리 형식의 트리 모듈에서 이름에 일반적으로 4.14 접두사가 있습니다).주의해야 할 것은 binfmt_script 모듈은 상술한shebang행을 해석하고 목표 시스템에서 스크립트를 실행하는 것을 책임진다. (shebang지원이 실제로는 내부 핵 자체에서 이루어지는 것이지 셸이나 다른 수호 프로세스/프로세스에서 이루어지는 것이 아니라는 것을 모두가 알고 있는 것은 아니다.)

    사용자 공간에서 지원하는 바이너리 형식 확장


    그러나 우리가 결론을 내린 이상 shebang은 Go 스크립트의 최선의 선택이 아니라 다른 것이 필요한 것 같다.놀랍게도 리눅스 커널은 이미 하나"something else" binary support module가 있고, 그것은 적당한 명칭binfmt_을 가지고 있다.이 모듈은 관리자가 양호한 binfmt_misc 인터페이스와 iswell-documented를 정의하여 사용자 공간에서 각종 실행 가능한 형식에 대한 지원을 직접 추가할 수 있도록 합니다.
    the documentation 파일에 대한 바이너리 형식 설명을 설정하기 위해 procfs 을 따릅니다.먼저 안내서에서 특수.go 파일 시스템을 binfmt_misc 에 마운트할 것을 알려 줍니다.만약 비교적 새로운 시스템 기반 리눅스 버전을 사용한다면, 시스템 d는 기본적으로 이 특수한 mountautomount 단원을 설치할 수 있기 때문에 파일 시스템을 설치했을 것입니다.다시 확인하려면 다음을 실행하십시오.
    $ mount | grep binfmt_misc
    systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=27,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)
    
    또 다른 방법은 /proc/sys/fs/binfmt_misc에 파일이 있는지 확인하는 것입니다. 정확하게 설치된 /proc/sys/fs/binfmt_misc 파일 시스템은 이 디렉터리에 binfmt_miscregister 라는 특수 파일을 최소한 두 개 만들 것입니다.
    다음은 status 스크립트가 운영 체제에 종료 코드를 정확하게 전달하기를 원하기 때문에 사용자 정의 gorun 패키지를 "해석기"로 해야 합니다.
    $ go get github.com/erning/gorun
    $ sudo mv ~/go/bin/gorun /usr/local/bin/
    
    기술적으로 말하자면, 우리는 .gogorun 또는 다른 시스템 경로로 이동할 필요가 없다. 왜냐하면 /usr/local/bin 어떻게든 해석기의 완전한 경로가 필요하지만, 시스템은 임의의 권한으로 이 실행 가능한 파일을 실행할 수 있기 때문에 안전 측면에서 파일에 대한 접근을 제한하는 것은 좋은 생각이다.
    이제 간단한 toy Go 스크립트 binfmt_misc 를 만들고 성공적으로 설명할 수 있는지 검증합니다.스크립트:
    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        s := "world"
    
        if len(os.Args) > 1 {
            s = os.Args[1]
        }
    
        fmt.Printf("Hello, %v!", s)
        fmt.Println("")
    
        if s == "fail" {
            os.Exit(30)
        }
    }
    
    매개변수 전달 및 오류 처리가 예상대로 작동하는지 확인합니다.
    $ gorun helloscript.go
    Hello, world!
    $ echo $?
    0
    $ gorun helloscript.go gopher
    Hello, gopher!
    $ echo $?
    0
    $ gorun helloscript.go fail
    Hello, fail!
    $ echo $?
    30
    
    현재 우리는 helloscript.go 모듈이 binfmt_misc 실행 .go 파일을 어떻게 사용하는지 알려야 한다.the documentation 이후에 이 설정 문자열이 필요합니다. gorun 기본적으로 시스템에 알려줍니다. "확장자가 :golang:E::go::/usr/local/bin/gorun:OC 인 실행 가능한 파일을 만났으면 .go 해석기로 실행하십시오."문자열 끝에 있는 /usr/local/bin/gorun 로고는 스크립트가 해석기 바이너리 파일에 설정된 정보와 권한 위치에 따라 실행되지 않고 스크립트 자체에 설정된 소유자 정보와 권한 위치에 따라 실행되는지 확인합니다.따라서 Go 스크립트의 실행 동작은 Linux의 다른 실행 가능한 파일과 스크립트와 같습니다.
    새 Go 스크립트 바이너리 형식을 등록합니다.
    $ echo ':golang:E::go::/usr/local/bin/gorun:OC' | sudo tee /proc/sys/fs/binfmt_misc/register
    :golang:E::go::/usr/local/bin/gorun:OC
    
    형식이 성공적으로 등록되면 OC 디렉토리에 새 파일 golang 이 나타납니다.마지막으로, 우리는 이 컴퓨터에서 /proc/sys/fs/binfmt_misc 파일을 실행할 수 있다.
    $ chmod u+x helloscript.go
    $ ./helloscript.go
    Hello, world!
    $ ./helloscript.go gopher
    Hello, gopher!
    $ ./helloscript.go fail
    Hello, fail!
    $ echo $?
    30
    
    그렇습니다!이제 우리는 자신의 취향에 따라 편집할 수 있다.go. 변경 사항은 다음에 파일을 실행할 때 바로 볼 수 있다.또한 이전의shebang 방법과 달리 우리는 언제든지 helloscript.go 이 파일을 진정한 실행 가능한 파일로 컴파일할 수 있습니다.

    좋은 웹페이지 즐겨찾기