-
[Bash] 코딩 규칙 및 모범 사례Programming/Shell 2020. 1. 17. 16:55
Naming and Styles
Tabs and Spaces
ㅁ Tab 사용금지
ㅁ 후행 공백 제거
Pipe
ㅁ inline 파이프와 display 파이프가 있는데, 파이프가 너무 짧은 경우를 제외하고 display 파이프를 사용하여 명확하게 구분하자
ㅁ display 파이프를 사용할 때 파이프( | ) 기호를 명령문 시작 부분에 넣자. (줄 끝에 넣지말자)This is an inline pipe: "$(ls -la /foo/ | grep /bar/)" # The following pipe is of display form: every command is on # its own line. _foobar="$( \ ls -la /foo/ \ | grep /bar/ \ | awk '{print $NF}')" _generate_long_lists \ | while IFS= read -r _line; do _do_something_fun done
Variable names
ㅁ 변수의 범위에 따라 변수의 이름을 지정
ㅁ 글로벌 변수는 대문자 ( EX. THIS_IS_A_USERXXX )
ㅁ 그 외에 변수는 소문자, 밑줄(_)로 시직한다. 밑줄(_)의 주요 목적은 $변수가 사용될때 거리를 만들어서 코드를 쉽게 읽을 수 있다. (EX. $_this_is_a_xx)
ㅁ 함수 정의 내부의 모든 로컬 변수는 local 명령문으로 선언하자
ㅁ local 명령문에 여러 변수를 선언할 수 있지만 그렇게하면 코드를 읽을 수 없기 때문에 각 라인별로 선언하자# The following variable can be provided by user at run time. D_ROOT="${D_ROOT:-}" # All variables inside `_my_def` are declared with `local` statement. _my_def() { local _d_tmp="/tmp/" local _f_a= local _f_b= # This is good, but it's quite a mess local _f_x= _f_y= }
Function names
ㅁ 내부 함수의 이름은 밑줄(_)로 시작
ㅁ 밑줄(_)을 사용하여 동사와 명사를 붙이고, 낙타대문자를 사용하지 말자 (EX. ThisIsNotMyStle; use this_is_my_style )
ㅁ 두 밑줄(__)을 사용하여 다른 내부 함수에서 사용하는 경우에 사용하자Error handling
Sending instructions
ㅁ 모든 오류는 STDERR으로 보냄
ㅁ STDOUT에 오류/경고 메시지를 보내지 말자
ㅁ echo 메시지를 직접 인쇄하는데 사용하지 말고, 대신 래퍼를 사용 (warn, err, die) 사용하자_warn() { echo >&2 ":: $*" } _die() { echo >&2 ":: $*" exit 1 }
ㅁ 다른 기능의 오류를 처리하지 말고, 각 함수는 자체 정의 내에서 자체 구현으로 오류 및 메시지를 처리하자
_my_def() { _foobar_call if [[ $? -ge 1 ]]; then echo >&2 "_foobar_call has some error" _error "_foobar_call has some error" return 1 fi }
ㅁ 위에 예에서 _my_def에 대한 오류를 처리하는데, _foorbar_call 좋은 생각이 아니다
_foobar_call() { # do something if [[ $? -ge 1 ]]; then _error "$FUNCNAME has some internal error" fi } _my_def() { _foobar_call || return 1 }
Catch up with $?
ㅁ $? 마지막의 리턴 코드를 얻는데 사용되는데, 가장 좋은 방법은 변수를 로컬 변수에 저장하는 것이다_do_something_critical local _ret="$?" # from now, $? is zero, because the latest statement (assignment) # (always) returns zero. _do_something_terrible echo "done" if [[ $? -ge 1 ]]; then # Bash will never reach here. Because "echo" has returned zero. fi
ㅁ $? 는 매우 유용하지만, 너무 믿지 말자
ㅁ set -e 와 $? 를 함께 사용하지 말자
Pipe error handling
ㅁ 파이프는 구성 요소의 리턴 코드를 PIPESTATUS 배열에 저장한다
ㅁ 변수는 파이프 뒤의 하위 파이프에서만 ONCE를 사용할 수 있다 {shell, process }echo test | fail_command | something_else local _ret_pipe=( "${PIPESTATUS[@]}" )
ㅁ _ret_pipe 배열의 0 이외에 것이 포함 된 경우 일부 파이프 구성 요소가 실패했지 확인하자
# Note: # This function only works when it is invoked # immediately after a pipe statement. _is_good_pipe() { echo "${PIPESTATUS[@]}" | grep -qE "^[0 ]+$" } _do_something | _do_something_else | _do_anything _is_good_pipe \ || { echo >&2 ":: Unable to do something" }
Automatic error handling
set -u (매개변수 확장 시 설정되어 있지 않은 변수를 오류로 간주)
ㅁ 항상 set -u 를 사용하여 선언되지 않은 변수를 사용하지 않도록 하자
ㅁ set -u 는 변수를 선언하고 빈 값으로 설정하면 어쩔 수 없다.
set -e (0이 아닌 상태값이면 증시 종료)
ㅁ 스크립트를 전체 배포 할때는 주의하자 (가능하면 사용자가 선택할 수 있는 옵션)
ㅁ set -e 옵션을 이용하여 프로그램의 에러를 검출하고 싶을 때는 리턴코드를 잘 생각하고 사용하자
ㅁ 되도록 trap을 이용하여 에러 검출하여 처리하는 로직이 좋다set -e _do_some_critical_check if [[ $? -ge 1 ]]; then echo "Oh, you will never see this line" fi
ㅁ _do_some_critical_check에 실패, 스크립트는 종료하고 다음 코드는 예고없이 건너 뛴다
(false && true); echo not here { false && true; }; echo here
Techniques
Make your script a library
ㅁ 첫번째 function 사용하는데, 스크립트에 직접 지시문을 작성하는 대신 래퍼가 존재한다. 아래 방법은 좋지 않다: do something cool : do something great
ㅁ function 에 포함시키는 것이 좋다
_default_tasks() { : do something cool : do something great }
ㅁ 마지막 줄에서 스크립트를 실행할 수 있다
case "${@:-}" in ":") echo "File included." ;; "") _default_tasks ;; esac
ㅁ 다른 스크립트에서 코드를 실행하지 않고도 스크립트를 쉽게 포함시킬 수 있다
ㅁ 간단한 기술을 발전시킴으로써 스크립트를 디버그하거나 스크립트 동작을 변경할 수 있는 더 많은 옵션을 갖는다# from other script source "/path/to_the_previous_script.sh" ":"
Quick self-doc
ㅁ grep을 다음 예제와 같이 사용하여 아름다운 자체 문서를 작성할 수 있다._func_1() { #public: Some quick introduction : } _func_2() { #public: Some other tasks : } _quick_help() { LANG=en_US.UTF_8 grep -E '^_.+ #public' "$0" \ | sed -e 's|() { #public: |☠|g' \ | column -s"☠" -t \ | sort }
ㅁ _quick_help를 실행하면 다음과 같다
_func_1 Some quick introduction _func_2 Some other tasks
No excuse
ㅁ 인수 목록이 비어 있으면 아무 것도하지 않고 즉시 종료해라
ㅁ 기본 제약 조건이 설정되지 않은 경우 종료해라
Meta programming
ㅁ Bash는 다음과 같이 매우 강력한 특징을 가지고 있다.my_func() { echo "This is my function`" } echo "The definition of my_func" declare -f my_func # <snip>
ㅁ 왜 중요할까? (예를 들어 기능을 원격으로 전송하고 ssh를 통해 해당 기능을 제외시킴)
ㅁ ssh를 통해 많은 지시를 보내야 할 때, 스크립트를 읽을 수 있도록 도와준다 (그러나 ssh 세션에 대화형 입력 스트림 누락됨){ declare -f my_func # send function definition echo "my_func" # execution instruction } \ | ssh some_server
Removing with care
ㅁ 파일과 디렉토리를 올바르게 제거하기 힘들다
ㅁ 백업 옵션과 함께 rm을 사용하는 것을 고려해야한다
ㅁ rm 인수에 몇 가지 변수를 사용하면 불변으로 만들 수 있다export _temporary_file=/path/to/some/file/ readonly _temporary_file # <snip> rm -fv "$_temporary_file"
Shell or Python/Ruby/etc
ㅁ 한가지 중요한 요인은 bash가 메모리 효율이 좋지않다. 즉 여러 개의 데이터를 가지고 있다면, 그 데이터에 일정 부분을 추출하고 싶을 때마다 데이터를 다시 로드할 수 있다
ㅁ 스크립트가 어떤 종류의 데이터라도 해석해야 할 때, 앞으로 나아가서 다른 언어로 스크립트를 다시 쓰는 것이 좋다Good lessons
See also in LESSONS.md (https://github.com/icy/bash-coding-style/blob/master/LESSONS.md).
Resources
Authors. License
원저자는 Anh K. Huynh이며 원작은 TheSLinux의 일부였습니다.
일부 기고자들이 오류를 수정하고 스타일을 개선하는 데 도움을 받았습니다. 그들은 또한 저자입니다.
이 작업은 MIT 라이센스에 따라 릴리스됩니다.
출처: <https://github.com/icy/bash-coding-style>
'Programming > Shell' 카테고리의 다른 글
[Bash] 스크립트 제어 (0) 2017.12.11 [Bash] 쉘 스크립트 개요 (0) 2017.08.16