직장에서는 bash 스크립트를 많이 작성합니다. 내 상사는 다음 예와 유사하게 전체 스크립트를 함수로 나눌 것을 제안했습니다.
#!/bin/bash
# Configure variables
declare_variables() {
noun=geese
count=three
}
# Announce something
i_am_foo() {
echo "I am foo"
sleep 0.5
echo "hear me roar!"
}
# Tell a joke
walk_into_bar() {
echo "So these ${count} ${noun} walk into a bar..."
}
# Emulate a pendulum clock for a bit
do_baz() {
for i in {1..6}; do
expr $i % 2 >/dev/null && echo "tick" || echo "tock"
sleep 1
done
}
# Establish run order
main() {
declare_variables
i_am_foo
walk_into_bar
do_baz
}
main
더 많은 주석과 약간의 줄 간격으로 확립될 수 있는 "가독성" 외에 이것을 수행할 이유가 있습니까?
스크립트를 더 효율적으로 실행하게 합니까(실제로는 그 반대일 것으로 예상합니다), 아니면 위에서 언급한 가독성 이상으로 코드를 수정하기 더 쉽게 합니까? 아니면 이것은 단지 스타일 선호에 불과한 것일까요?
스크립트에서는 이를 잘 보여주지 않지만 실제 스크립트에서 함수의 "실행 순서"는 수행된 작업과 설정된 작업 walk_into_bar
에 따라 매우 선형적인 경향이 있으므로 실행을 교환할 수 있습니다. 임의로 시퀀스는 우리가 일반적으로 수행하는 작업이 아닙니다. 예를 들어, 갑자기 물건을 뒤쪽 에 넣고 싶지 않을 것입니다 . 그러면 물건이 망가질 것입니다.i_am_foo
do_baz
walk_into_bar
declare_variables
walk_into_bar
위 스크립트를 작성하는 방법의 예는 다음과 같습니다.
#!/bin/bash
# Configure variables
noun=geese
count=three
# Announce something
echo "I am foo"
sleep 0.5
echo "hear me roar!"
# Tell a joke
echo "So these ${count} ${noun} walk into a bar..."
# Emulate a pendulum clock for a bit
for i in {1..6}; do
expr $i % 2 >/dev/null && echo "tick" || echo "tock"
sleep 1
done
답변1
가독성그건 같은거야. 하지만 더 많은 게 있어요모듈식그것만이 아니다. (반모듈식아마도 기능에 더 정확할 것입니다. )
함수에서 일부 변수를 지역 변수로 유지하여 증가할 수 있습니다.신뢰할 수 있음, 일이 지저분해질 가능성을 줄입니다.
함수의 또 다른 장점은재사용 성. 함수가 코딩되면 스크립트에서 여러 번 적용할 수 있습니다. 다른 스크립트로 포팅할 수도 있습니다.
귀하의 코드는 현재 선형적일 수 있지만 미래에는 선형 영역으로 이동할 수 있습니다.멀티스레딩, 또는다중 처리배쉬 세계에서. 함수에서 작업하는 방법을 배우면 병렬 처리로 이동할 준비가 된 것입니다.
한 가지 더 추가할 사항이 있습니다. Etsitpab Nioliv가 아래 설명에서 알 수 있듯이 기능에서 일관된 엔터티로 리디렉션하는 것은 쉽습니다. 그러나 기능 리디렉션에는 또 다른 측면이 있습니다. 즉, 함수 정의에 따라 리디렉션을 설정할 수 있습니다. 예를 들어. :
f () { echo something; } > log
이제 함수 호출에는 명시적인 리디렉션이 필요하지 않습니다.
$ f
이렇게 하면 많은 중복을 피할 수 있고 안정성이 향상되며 정리된 내용을 유지하는 데 도움이 됩니다.
당신은 또한 볼 수 있습니다
답변2
이 글을 읽은 후 나는 동일한 스타일의 bash 프로그래밍을 사용하기 시작했습니다.Kfir Lavi의 블로그 게시물 "방어적 Bash 프로그래밍". 그는 타당한 이유를 많이 제시하지만 개인적으로 다음이 가장 중요하다고 생각합니다.
프로세스가 설명적이 됩니다. 코드의 특정 부분이 수행해야 하는 작업을 파악하기가 더 쉽습니다. 코드 월 대신 "아, 이
find_log_errors
함수는 해당 로그 파일에서 오류를 읽었습니다"라는 메시지가 표시됩니다. 신은 긴 스크립트 중간에 어떤 유형의 정규 표현식이 있는지 알고 있으므로 awk/grep/sed 행을 찾는 것과 비교해 보세요. 주석이 없으면 거기에서 무엇을 하는지 알 수 없습니다.및 를 묶어서
set -x
함수를 디버깅 할 수 있습니다set +x
. 나머지 코드가 제대로 작동한다는 것을 알게 되면 이 트릭을 사용하여 해당 특정 기능만 디버깅하는 데 집중할 수 있습니다. 물론, 스크립트의 일부를 첨부할 수 있지만, 너무 길면 어떻게 될까요? 이렇게 하는 것이 더 쉽습니다.set -x parse_process_list set +x
인쇄 사용법은 와 동일합니다
cat <<- EOF . . . EOF
. 코드를 더욱 전문적으로 만들기 위해 여러 번 사용했습니다. 게다가parse_args()
기능getopts
도 상당히 편리합니다. 다시 말하지만, 이는 거대한 텍스트 벽처럼 스크립트에 모든 것을 밀어 넣는 것보다 가독성에 도움이 됩니다. 이것들은 재사용하기도 쉽습니다.
분명히 이는 C, Java 또는 Vala를 알고 있지만 bash 경험이 제한적인 사람이 더 읽기 쉽습니다. 효율성 측면에서 할 수 있는 일은 많지 않습니다. bash 자체는 가장 효율적인 언어가 아니며 사람들은 속도와 효율성을 위해 Perl과 Python을 선호합니다. 그러나 다음과 같은 nice
기능을 사용할 수 있습니다 .
nice -10 resource_hungry_function
이렇게 하면 코드의 모든 줄에서 nice를 호출하는 것에 비해 많은 입력 작업이 줄어들고, 낮은 우선 순위에서 스크립트의 일부만 실행하려는 경우에 유용합니다.
제 생각에는 백그라운드에서 여러 명령문을 실행하려는 경우 백그라운드에서 함수를 실행하는 것도 도움이 됩니다.
이 스타일을 사용하는 몇 가지 예는 다음과 같습니다.
답변3
내 의견에서 나는 함수의 세 가지 장점을 언급했습니다.
정확성을 테스트하고 확인하는 것이 더 쉽습니다.
함수는 향후 스크립트에서 쉽게 재사용할 수 있습니다(출처)
당신의 상사가 그들을 좋아합니다.
그리고 세 번째 항목의 중요성을 결코 과소평가하지 마십시오.
또한 문제를 해결하고 싶습니다.
...따라서 실행 순서를 임의로 바꾸는 것은 일반적으로 수행하는 작업이 아닙니다. 예를 들어, 갑자기 물건을
declare_variables
뒤쪽 에 넣고 싶지 않을 것입니다walk_into_bar
. 그러면 물건이 망가질 것입니다.
코드를 함수로 나누는 것의 이점을 얻으려면 함수를 가능한 한 독립적으로 만들어야 합니다. 다른 곳에서 사용되지 않는 변수가 필요한 경우 walk_into_bar
해당 변수를 에서 정의하고 로컬로 만들어야 합니다 walk_into_bar
. 코드를 함수로 나누고 상호의존성을 최소화하는 과정은 코드를 더 명확하고 단순하게 만들어야 합니다.
이상적으로는 함수를 개별적으로 테스트하기 쉬워야 합니다. 상호 작용으로 인해 쉽게 테스트할 수 없는 경우 이는 리팩토링을 통해 이점을 얻을 수 있음을 나타냅니다.
답변4
코드를 함수로 분해하는 이유는 C/C++, Python, Perl, Ruby 또는 기타 프로그래밍 언어의 코드를 분해하는 이유와 동일합니다. 더 깊은 이유는 추상화입니다. 하위 수준 작업을 상위 수준 기본 요소(함수)로 캡슐화하므로 작업 수행 방법에 대해 걱정할 필요가 없습니다. 동시에, 코드는 더 읽기 쉽고 유지 관리하기 쉬워지고 프로그램 논리는 더 명확해집니다.
그러나 귀하의 코드를 보면 변수를 선언하는 함수가 있다는 것이 이상하다는 것을 알았습니다.