코드 를 깔끔 하고 과정 이 뚜렷 한 BASH Shell 프로 그래 밍 기법
프로그램 을 장애 로부터 보호 하고 코드 를 깨끗하게 유지 하 는 방법 을 알려 드 리 겠 습 니 다.
1. 변경 할 수 없 는 전역 변수
1. 전역 변 수 를 적 게 사용 합 니 다. 2. 대문자 로 이름 짓 기 3. 성명 만 읽 기 4. 숨겨 진 $0, $1 등 을 전역 변수 로 대체 합 니 다.
내 프로그램 에서 자주 사용 하 는 전역 변수:
readonly PROGNAME=$(basename $0)
readonly PROGDIR=$(readlink -m $(dirname $0))
readonly ARGS="$@"
2. 모든 것 이 국부 적 이다.
모든 변 수 는 국부 적 이 어야 한다.
change_owner_of_file() {
local filename=$1
local user=$2
local group=$3
chown $user:$group $filename
}
change_owner_of_files() {
local user=$1; shift
local group=$1; shift
local files=$@
local i
for i in $files
do
chown $user:$group $i
done
}
1. 자체 주석 (self documenting) 의 인자 2. 보통 순환 용 변수 i 로 서 국부 변수 로 설명 하 는 것 이 중요 합 니 다.3. 국부 변 수 는 전역 에 작용 하지 않 는 다.
kfir@goofy ~ $ local a
bash: local: can only be used in a function
3. main ()
1. 모든 변수의 국 지성 을 유지 하 는 데 도움 이 됩 니 다. 2. 직관 적 인 함수 식 프로 그래 밍 3. 코드 에서 유일한 전역 명령 은 main 입 니 다.
main() {
local files="/tmp/a /tmp/b"
local i
for i in $files
do
change_owner_of_file kfir users $i
done
}
main
4. 모든 것 이 함수 입 니 다.
유일 하 게 전역 적 으로 실행 되 는 코드 는: - 가 변 적 이지 않 은 전역 변수 성명 - main () 함수 입 니 다.
1. 코드 를 깨끗하게 유지 합 니 다. 2. 과정 이 뚜렷 해 집 니 다.
main() {
local files=$(ls /tmp | grep pid | grep -v daemon)
}
temporary_files() {
local dir=$1
ls $dir \
| grep pid \
| grep -v daemon
}
main() {
local files=$(temporary_files /tmp)
}
1. 두 번 째 예 는 훨씬 좋다.파일 찾기 는 temporaryfiles () 의 문제 가 main () 의 문제 가 아 닙 니 다.이 코드 는 temporaryfiles () 의 유닛 테스트 도 테스트 할 수 있 습 니 다.
2. 첫 번 째 예 를 꼭 시도 해 보 려 면 main 알고리즘 과 의 잡 채 를 찾 을 수 있 습 니 다.
test_temporary_files() {
local dir=/tmp
touch $dir/a-pid1232.tmp
touch $dir/a-pid1232-daemon.tmp
returns "$dir/a-pid1232.tmp" temporary_files $dir
touch $dir/b-pid1534.tmp
returns "$dir/a-pid1232.tmp $dir/b-pid1534.tmp" temporary_files $dir
}
보시 다시 피 이 테스트 는 main () 에 관심 이 없습니다.
5. 디 버 깅 함수
밴드 - x 로고 실행 프로그램:
bash -x my_prog.sh
작은 코드 만 디 버 깅 하고 set - x 와 set + x 를 사용 하면 set - x 와 set + x 에 포 함 된 현재 코드 에 만 디 버 깅 정 보 를 인쇄 합 니 다.
temporary_files() {
local dir=$1
set -x
ls $dir \
| grep pid \
| grep -v daemon
set +x
}
함수 이름과 인자 인쇄:
temporary_files() {
echo $FUNCNAME $@
local dir=$1
ls $dir \
| grep pid \
| grep -v daemon
}
호출 함수:
temporary_files /tmp
표준 출력 으로 출력:
temporary_files /tmp
6. 코드 의 선명 도
이 코드 는 무엇 을 했 습 니까?
main() {
local dir=/tmp
[[ -z $dir ]] \
&& do_something...
[[ -n $dir ]] \
&& do_something...
[[ -f $dir ]] \
&& do_something...
[[ -d $dir ]] \
&& do_something...
}
main
코드 말 하 라 고:
is_empty() {
local var=$1
[[ -z $var ]]
}
is_not_empty() {
local var=$1
[[ -n $var ]]
}
is_file() {
local file=$1
[[ -f $file ]]
}
is_dir() {
local dir=$1
[[ -d $dir ]]
}
main() {
local dir=/tmp
is_empty $dir \
&& do_something...
is_not_empty $dir \
&& do_something...
is_file $dir \
&& do_something...
is_dir $dir \
&& do_something...
}
main
7. 줄 마다 한 가지 일 만 합 니 다.
구분자.예 를 들 면:
temporary_files() {
local dir=$1
ls $dir | grep pid | grep -v daemon
}
훨씬 간결 하 게 쓸 수 있다.
temporary_files() {
local dir=$1
ls $dir \
| grep pid \
| grep -v daemon
}
기호 축소 진행 의 시작
기호 가 줄 끝 에 있 는 나 쁜 예: (번역 주: 원문 은 이 예 에서 temporary files () 코드 세그먼트 를 사 용 했 습 니 다. 잘못 붙 인 것 같 습 니 다. 컨 텍스트 와 결합 하여 print dir if not empty () 여야 합 니 다.
print_dir_if_not_empty() {
local dir=$1
is_empty $dir && \
echo "dir is empty" || \
echo "dir=$dir"
}
좋 은 예: 우 리 는 줄 과 연결 기호 간 의 관 계 를 뚜렷하게 볼 수 있다.
print_dir_if_not_empty() {
local dir=$1
is_empty $dir \
&& echo "dir is empty" \
|| echo "dir=$dir"
}
8. 인쇄 용법
이렇게 하지 마 세 요.
echo "this prog does:..."
echo "flags:"
echo "-h print help"
그것 은 함수 일 것 이다.
usage() {
echo "this prog does:..."
echo "flags:"
echo "-h print help"
}
echo 는 줄 마다 반복 합 니 다.그래서 우 리 는 이 문 서 를 얻 었 다.
usage() {
cat < usage: $PROGNAME options
Program deletes files from filesystems to release space.
It gets config file that define fileystem paths to work on, and whitelist rules to
keep certain files.
OPTIONS:
-c --config configuration file containing the rules. use --help-config to see the syntax.
-n --pretend do not really delete, just how what you are going to do.
-t --test run unit test to check the program
-v --verbose Verbose. You can specify more then one -v to have more verbose
-x --debug debug
-h --help show this help
--help-config configuration help
Examples:
Run all tests:
$PROGNAME --test all
Run specific test:
$PROGNAME --test test_string.sh
Run:
$PROGNAME --config /path/to/config/$PROGNAME.conf
Just show what you are going to do:
$PROGNAME -vn -c /path/to/config/$PROGNAME.conf
EOF
}
줄 마다 진짜 탭 문자 '\t' 가 있어 야 합 니 다.
vim 에서 tab 가 4 개의 빈 칸 이 라면 이 명령 을 바 꿀 수 있 습 니 다.
:s/^ /\t/
9. 명령 행 매개 변수
이것 은 하나의 예 로 위의 usage 함수 의 용법 을 완성 했다.부터http://kirk.webfinish.com/2009/10/bash-shell-script-to-use-getopts-with-gnu-style-long-positional-parameters/이 코드 얻 기
cmdline() {
# got this idea from here:
# http://kirk.webfinish.com/2009/10/bash-shell-script-to-use-getopts-with-gnu-style-long-positional-parameters/
local arg=
for arg
do
local delim=""
case "$arg" in
#translate --gnu-long-options to -g (short options)
--config) args="${args}-c ";;
--pretend) args="${args}-n ";;
--test) args="${args}-t ";;
--help-config) usage_config && exit 0;;
--help) args="${args}-h ";;
--verbose) args="${args}-v ";;
--debug) args="${args}-x ";;
#pass through anything else
*) [[ "${arg:0:1}" == "-" ]] || delim="\""
args="${args}${delim}${arg}${delim} ";;
esac
done
#Reset the positional parameters to the short options
eval set -- $args
while getopts "nvhxt:c:" OPTION
do
case $OPTION in
v)
readonly VERBOSE=1
;;
h)
usage
exit 0
;;
x)
readonly DEBUG='-x'
set -x
;;
t)
RUN_TESTS=$OPTARG
verbose VINFO "Running tests"
;;
c)
readonly CONFIG_FILE=$OPTARG
;;
n)
readonly PRETEND=1
;;
esac
done
if [[ $recursive_testing || -z $RUN_TESTS ]]; then
[[ ! -f $CONFIG_FILE ]] \
&& eexit "You must provide --config file"
fi
return 0
}
당신 은 이렇게 우리 가 머리 에 정의 한 변 하지 않 는 ARGS 변 수 를 사용 합 니 다.
main() {
cmdline $ARGS
}
main
10. 단원 테스트
1. 더 높 은 언어 에서 중요 하 다.2. shunit 2 를 사용 하여 유닛 테스트 를 한다.
test_config_line_paths() {
local s='partition cpm-all, 80-90,'
returns "/a" "config_line_paths '$s /a, '"
returns "/a /b/c" "config_line_paths '$s /a:/b/c, '"
returns "/a /b /c" "config_line_paths '$s /a : /b : /c, '"
}
config_line_paths() {
local partition_line="$@"
echo $partition_line \
| csv_column 3 \
| delete_spaces \
| column 1 \
| colons_to_spaces
}
source /usr/bin/shunit2
df 명령 을 사용 하 는 다른 예 입 니 다:
DF=df
mock_df_with_eols() {
cat < Filesystem 1K-blocks Used Available Use% Mounted on
/very/long/device/path
124628916 23063572 100299192 19% /
EOF
}
test_disk_size() {
returns 1000 "disk_size /dev/sda1"
DF=mock_df_with_eols
returns 124628916 "disk_size /very/long/device/path"
}
df_column() {
local disk_device=$1
local column=$2
$DF $disk_device \
| grep -v 'Use%' \
| tr '
' ' ' \
| awk "{print \$$column}"
}
disk_size() {
local disk_device=$1
df_column $disk_device 2
}
여기 서 나 는 예외 가 하나 있다. 테스트 를 위해 서 나 는 전 국 역 에서 DF 를 읽 기만 하 는 것 이 아니 라 고 성명 했다.shunit 2 가 전역 함 수 를 바 꿀 수 없 기 때 문 입 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.