CLI를 구축할 때 argv, 옵션, 환경 변수, stdin, stdout 및 stderr에 대해 허용되는 규칙이 있습니까?

CLI를 구축할 때 argv, 옵션, 환경 변수, stdin, stdout 및 stderr에 대해 허용되는 규칙이 있습니까?

나는 명령줄 응용 프로그램이 얼마나 간단한지에 대해 이야기하는 경향이 있습니다. 일반적으로 저는 "그들은 표준 입력에서 읽고 표준 출력과 표준 오류에 기록합니다. 그런 다음 다음과 같은 다이어그램을 그렸습니다."라고 말합니다.

여기에 이미지 설명을 입력하세요.

하지만 그게 실제로 이야기의 끝은 아니라고 생각하기 시작했습니다. 명령줄 응용 프로그램은 표준 입력에서 읽고 표준 오류 및 표준 출력에 씁니다.

  • /etc구성 파일 읽기( , ~또는 등의 여러 위치에서 .)
  • 환경 변수 읽기
  • 명령줄 스위치 읽기
  • 명령줄 플래그 읽기
  • 명령줄 매개변수 읽기
  • 종료 상태 설정

명령줄 응용 프로그램은 다음과 같이 표시됩니다.

여기에 이미지 설명을 입력하세요.

객관적으로 말하면 이는 단순한 stdin, stdout 및 stderr보다 더 복잡합니다.

나는 하루 종일 명령줄 응용 프로그램을 사용합니다. 시간이 지나면서 나는 그들에 대한 내 자신의 의견과 직관을 발전시켰습니다.

  • 기준 - 일반적으로 매개변수가 아닌 데이터(사용하지 않는 한 xargs)
  • stdout - 제품, 바람직하게는 열 형식 데이터
  • stderr - 문제가 발생할 때 오류나 오류 메시지를 기록하는 데 사용됩니다.
  • 종료 상태 - 신성, 0은 성공, 1은 실패(또는 다른 종류의 실패)를 의미합니다.
  • 매개변수 - 중요하지만 표준과 다르게 읽음
  • 플래그 - 매개변수와 유사하지만 덜 중요함
  • 스위치 - 플래그와 유사하지만 켜거나 끌 수 있습니다.
  • 환경 변수 - 매개변수와 약간 비슷하지만 둘 사이에는 철학적인 차이가 있습니다.
  • 구성 파일 - 환경 변수와 약간 유사하여 스위치나 플래그를 제어할 수 있지만 이를 버전 제어에 유지하고 일반적으로 스위치와 플래그의 실망스러운 조합을 사용하지 않아도 되도록 하거나 모든 사람에게 표시할 수 있습니다. 도트 파일?

이 가이드는 제가 사용하는 다양한 명령줄 도구에 적용되는 경향이 있습니다. 하지만 다른 사람들이 사용할 수 있도록 만들 때 참고가 되었으면 좋겠습니다.

예를 들어 다음은 Ruby로 작성된 명령줄 애플리케이션입니다.

#!/usr/bin/env ruby
# somecli

require 'optparse'
require 'yaml'

options = {}

etc_config = File.join('etc', 'somecli')
if File.exist? etc_config
  options.merge! YAML.load_file(etc_config)
end

home_config = File.join(ENV['HOME'], '.somecli')
if File.exist? home_config
  options.merge! YAML.load_file(home_config)
end

current_working_directory_config = '.somecli'
if File.exist? current_working_directory_config
  options.merge! YAML.load_file(current_working_directory_config)
end

OptionParser.new do |opts|
  opts.on("-s", "--[no-]switch") do |s|
    options[:switch] = s
  end
  opts.on("-a", "--[no-]another-switch") do |as|
    options[:'another-switch'] = as
  end
  opts.on("-y", "--[no-]yet-another-switch") do |yas|
    options[:'yet-another-switch'] = yas
  end
  opts.on("-y", "--[no-]even-yet-another-switch") do |eyas|
    options[:'even-yet-another-switch'] = eyas
  end
  opts.on("--flag FLAG") do |f|
    options[:flag] = f
  end
end.parse!

puts "ARGV=#{ARGV.inspect}"
puts "options=#{options.inspect}"
puts "ENV['cats']=#{ENV['cats'].inspect}"
unless STDIN.tty?
  puts "STDIN.read=#{STDIN.read.inspect}"
end
$stderr.puts "stderr: hello world!"
$stdout.puts "stdout: hello world!"
exit 0

실행하면 다음과 같이 보입니다.

echo -n foo bar baz | ./somecli -s -f flap jacks; echo $?
ARGV=["jacks"]
options={:"another-switch"=>true, :"even-yet-another-switch"=>true, :switch=>true, :flag=>"flap"}
ENV['cats']="flapjacks"
STDIN.read="foo bar baz"
stderr: hello world!
stdout: hello world!
0

입력 및 출력 규칙과 디자인 결정을 안내하는 보다 공식적인 문서에 대한 링크를 추가 정보에 제공하고 싶습니다.

알아요POSIX시스템에 무엇을 설치할지 결정하는 데 사용할 수 있는 일반적인 유틸리티가 있습니다. 단, 명령줄 응용 프로그램을 구축할 때 다음 두 가지를 알고 싶습니다.

  1. 제가 놓친 명령줄 프로그램에 입력을 가져오는 다른 일반적인 방법이 있습니까?
  2. 다양한 입력 및 출력을 구성하는 방법에 대한 규칙에 대한 권위 있는 문서가 있습니까?

답변1

명령줄 유틸리티에 대한 일부 일반 지침은 POSIX.1/Single UNIX 사양에 문서화되어 있습니다.

바라보다섹션 12.2: 유틸리티 구문 가이드.

답변2

상식 외에는 어떤 관례도 없다고 생각합니다.

입력 및 출력 방법에 관해서, 또는 일반적으로 말하면,의사소통하다방법, 당신은 한 가지 방법을 언급했지만 그 중 일부만 언급했습니다. 파일을 읽고 쓰는 것입니다. (구성 파일을 읽는다고 언급했거나 일반적으로파일 설명자.)

파일과 유사하게 파이프와 소켓이 있습니다. 예를 들어. 방법으로 간주될 수 있는 TCP, UDP 또는 Unix 소켓프로세스 간 통신(IPC). 다른 유형의 IPC는 다음과 같습니다.

  • 공유 메모리와 매핑된 메모리
  • 신호
  • 신호
  • D 버스

관련 정보