سؤال

ماذا سيكون الخاص بك اقتراحات جيدة باش/ksh النصي قالب استخدام المعيار لجميع حديثا النصية ؟

وعادة ما تبدأ (بعد #! خط) مع علق بها رأس مع اسم الملف, ملخص, الاستخدام, عودة القيم المؤلف(ق) ، التغيير و سوف تناسب 80-شار خطوط.

جميع الوثائق خطوط أبدأ مع ضعف تجزئة الرموز ## حتى أستطيع أن البقرى لهم بسهولة و المحلية فار أسماء إرفاق مسبقا مع "__".

أي أفضل الممارسات ؟ نصائح ؟ تسمية الاتفاقيات ؟ ماذا عن عودة رموز ؟

التعليقات على التحكم في الإصدار :نحن نستخدم إس حسنا, ولكن آخر قسم في المؤسسة منفصل الريبو وهذا هو السيناريو.كيف أعرف من الاتصال مع Q ما إذا كان هناك أي @المؤلف المعلومات ؟ استخدام إدخالات مشابهة javadocs له وجاهته حتى في شل السياق ، IMHO لكن قد تكون خاطئة.

هل كانت مفيدة؟

المحلول

وكنت تمديد الجواب نورمان إلى 6 خطوط، وآخر تلك فارغ:

#!/bin/ksh
#
# @(#)$Id$
#
# Purpose
 

والسطر الثالث هو سلسلة تحديد التحكم في الإصدار - هو في الواقع الهجين مع علامة "@(#)" SCCS التي يمكن تحديدها من قبل (SCCS) what برنامج وسلسلة إصدار RCS التي يتم توسيع عندما يتم وضع الملف تحت RCS، وVCS الافتراضية يمكنني استخدام للاستخدام الخاص بي. برنامج ident RCS تلتقط شكل موسع من $Id$، والتي قد تبدو وكأنها $Id: mkscript.sh,v 2.3 2005/05/20 21:06:35 jleffler Exp $. السطر الخامس يذكرني أن السيناريو يجب أن يكون وصفا لغرضه في القمة. I استبدال كلمة مع وصف الفعلي من السيناريو (وهذا هو السبب وليس هناك القولون بعد ذلك، على سبيل المثال).

وبعد ذلك، هو في الأساس لا يوجد شيء القياسي لشيل. هناك شظايا القياسية التي تظهر، ولكن لا جزء القياسية التي تظهر في كل النصي. (تفترض بلدي المناقشة التي مخطوطات مكتوبة في بورن، كورن، أو POSIX (باش) الرموز قذيفة. هناك مناقشة منفصلة كليا عن سبب أي شخص وضع مشتق C شل بعد سيجيل #! يعيش في الخطيئة.)

وعلى سبيل المثال، يظهر هذا الرمز في بعض صورة أو شكل كلما يخلق النصي الملفات المتوسطة (مؤقتة):

tmp=${TMPDIR:-/tmp}/prog.$$
trap "rm -f $tmp.?; exit 1" 0 1 2 3 13 15

...real work that creates temp files $tmp.1, $tmp.2, ...

rm -f $tmp.?
trap 0
exit 0

والسطر الأول يختار دليل مؤقت، تعثر ل/ تمة إذا كان المستخدم لم يحدد بديل ($ TMPDIR هناك اعتراف واسع جدا وموحدة من قبل POSIX). ومن ثم يخلق بادئة اسم الملف بما في ذلك معرف العملية. هذا ليس مقياسا الأمن؛ ذلك هو مقياس التزامن بسيط، ومنع حالات متعددة من البرنامج النصي من الدوس على بيانات بعضها البعض. (لمزيد من الأمان، استخدم أسماء الملفات غير متوقعة في دليل غير العام.) يضمن السطر الثاني أن "rm" ويتم تنفيذ أوامر "exit" إذا تلقى قذيفة أي من الإشارات SIGHUP (1)، SIGINT (2 )، SIGQUIT (3)، SIGPIPE (13) أو SIGTERM (15). يزيل "rm" قيادة أي ملفات الوسيطة التي تتناسب مع القالب. يضمن الأمر exit أن الوضع غير الصفر، مما يدل على نوع من الخطأ. و"trap 'من 0 يعني أن يتم تنفيذ التعليمات البرمجية أيضا إذا كانت مخارج قذيفة لأي سبب من الأسباب - أنها تغطي الإهمال في قسم ملحوظ" العمل الحقيقي ". رمز في نهاية ثم إزالة أي ملفات مؤقتة على قيد الحياة، <م> قبل رفع فخ على الخروج، وأخيرا يخرج مع (النجاح) حالة الصفر. من الواضح، إذا كنت تريد الخروج مع وضع آخر، قد - فقط للتأكد من تعيينها في متغير قبل تشغيل rm وtrap خطوط، ومن ثم استخدام exit $exitval

وأنا عادة استخدام التالية لإزالة المسار ولاحقة من البرنامج النصي، حتى أتمكن من استخدام $arg0 عند الإبلاغ عن الأخطاء:

arg0=$(basename $0 .sh)

وأنا غالبا ما تستخدم وظيفة قذيفة الإبلاغ عن الأخطاء:

error()
{
    echo "$arg0: $*" 1>&2
    exit 1
}

وإذا كان هناك واحد فقط أو ربما اثنين مخارج خطأ، وأنا لا تهتم وظيفة. إذا كان هناك أي أكثر من ذلك، وأنا لا لأنه يبسط الترميز. أنا أيضا إنشاء وظائف أكثر أو أقل تفصيلا دعا usage لإعطاء ملخص لكيفية استخدام الأمر - مرة أخرى، إلا إذا كان هناك أكثر من مكان واحد حيث سيتم استخدامه

وجزء موحدة الى حد ما آخر هو حلقة خيار التوزيع، وذلك باستخدام في getopts قذيفة المدمج في:

vflag=0
out=
file=
Dflag=
while getopts hvVf:o:D: flag
do
    case "$flag" in
    (h) help; exit 0;;
    (V) echo "$arg0: version $Revision$ ($Date$)"; exit 0;;
    (v) vflag=1;;
    (f) file="$OPTARG";;
    (o) out="$OPTARG";;
    (D) Dflag="$Dflag $OPTARG";;
    (*) usage;;
    esac
done
shift $(expr $OPTIND - 1)

وأو:

shift $(($OPTIND - 1))

ونقلت حول "$ OPTARG" المساحات مقبض في الحجج. وDflag غير تراكمية، ولكن التدوين المستخدمة هنا يفقد المسار من مسافات في الحجج. هناك (غير قياسي) طرق للتغلب على هذه المشكلة أيضا.

وأول تدوين التحول يعمل مع أي قذيفة (أو أن تفعل إذا كنت العودة القراد بدلا من '$(...) ". وحد ذاتهاكوند يعمل في قذائف الحديثة؛ قد يكون هناك بديل مع أقواس مربعة بدلا من الأقواس، ولكن هذا يعمل حتى أنا لم يهتم للعمل على ما هي.

وخدعة واحدة النهائية في الوقت الراهن هو أنني في كثير من الأحيان يكون كل من حكومة الوحدة الوطنية وعلى بعد GNU غير نسخة من برامج حولها، وأريد أن أكون قادرا على اختيار الذي استعمل. كثير من كتاباتي، لذلك، استخدام المتغيرات مثل:

: ${PERL:=perl}
: ${SED:=sed}

وبعد ذلك، عندما كنت في حاجة لاستدعاء بيرل أو sed، يستخدم النصي $PERL أو $SED. هذا يساعدني عندما يتصرف شيء مختلف - يمكنني اختيار النسخة التشغيلي - أو أثناء تطوير البرنامج النصي (I يمكن إضافة خيارات خارج التصحيح الوحيد للأمر دون تعديل البرنامج النصي). (راجع شل التوسع المعلمة للحصول على معلومات عن و${VAR:=value} والرموز ذات الصلة).

نصائح أخرى

وأنا استخدم أول مجموعة من ## خطوط لتوثيق الاستخدام. لا أستطيع أن أتذكر الآن حيث رأيت لأول مرة هذا.

#!/bin/sh
## Usage: myscript [options] ARG1
##
## Options:
##   -h, --help    Display this message.
##   -n            Dry-run; only show what would be done.
##

usage() {
  [ "$*" ] && echo "$0: $*"
  sed -n '/^##/,/^$/s/^## \{0,1\}//p' "$0"
  exit 2
} 2>/dev/null

main() {
  while [ $# -gt 0 ]; do
    case $1 in
    (-n) DRY_RUN=1;;
    (-h|--help) usage 2>&1;;
    (--) shift; break;;
    (-*) usage "$1: unknown option";;
    (*) break;;
    esac
  done
  : do stuff.
}

ويجب أن يكون أي التعليمات البرمجية التي يتم سيفرج عنه في البرية رأس القصير التالي:

# Script to turn lead into gold
# Copyright (C) 2009 Joe Q Hacker - All Rights Reserved
# Permission to copy and modify is granted under the foo license
# Last revised 1/1/2009

والحفاظ على سجل التغيير تسير في رؤوس code عبارة عن ردة من عندما كانت أنظمة التحكم في الإصدار غير مريح بشكل رهيب. ويظهر تاريخ التعديل الأخير شخص كيفية القديمة السيناريو هو.

إذا كنت على وشك أن الاعتماد على bashisms، استخدم #! / بن / سحق، وليس / بن / ش، كما sh غير الاحتجاج POSIX من أي قذيفة. حتى لو / بن / نقاط SH لسحق، سيتم تشغيل العديد من الميزات قبالة إذا كنت تشغيله عن طريق / بن / ش. ومعظم توزيعات لينكس لا تأخذ البرامج النصية التي تعتمد على bashisms، في محاولة لتكون محمولة.

للي، والتعليقات في البرامج النصية قذيفة هي نوع من سخيفة ما لم تقرأ شيئا مثل:

# I am not crazy, this really is the only way to do this

وشل برمجة بسيطة جدا أن (ما لم كتاباتك مظاهرة لتعليم شخص ما كيف نفعل ذلك) رمز تقريبا دائما يغني نفسه.

وبعض القذائف لا أحب أن يكون الطعام كتبته المتغيرات "المحلية". أعتقد أن هذا اليوم BUSYBOX (قذيفة الإنقاذ المشتركة) هو واحد منهم. جعل GLOBALS_OBVIOUS بدلا من ذلك، من الأسهل بكثير للقراءة، وخاصة عند التصحيح عبر / بن / ش -x ./script.sh.

وبلدي تفضيل شخصي هو السماح منطق تتحدث عن نفسها والتقليل من العمل للمحلل. على سبيل المثال، كثير من الناس قد يكتب:

if [ $i = 1 ]; then
    ... some code 
fi

وحيث كنت فقط:

[ $i = 1 ] && {
    ... some code
}

وبالمثل، شخص ما قد يكتب:

if [ $i -ne 1 ]; then
   ... some code
fi

... حيث فما استقاموا لكم فاستقيموا:

[ $i = 1 ] || {
   ... some code 
}

والمرة الوحيدة التي يمكنني استخدام تقليدية اذا / ثم / آخر هو ما إذا كان هناك أحد آخر، إذا لرمي في هذا المزيج.

وهناك مثال مجنون فظيعة من جيد جدا كود القشرة المحمولة يمكن دراستها من قبل مجرد عرض 'تكوين' النصي في معظم حزم البرمجيات الحرة التي تستخدم autoconf. أقول مجانين بسبب خطوطها 6300 من التعليمات البرمجية التي يلبي كل نظام لرجل معروف لديها UNIX مثل قذيفة. كنت لا تريد هذا النوع من سخام، ولكن من المثير للاهتمام أن دراسة بعض قابلية مختلف الخارقة داخل .. مثل أن تكون لطيفة لأولئك الذين يمكن أن نشير / بن / ش إلى zsh:)

والنصيحة الوحيدة أخرى وأستطيع أن أعطي لمشاهدة التوسع بك هنا، مستندات، أي

cat << EOF > foo.sh
   printf "%s was here" "$name"
EOF

... هو الذهاب الى توسيع $ اسم، عندما تريد على الارجح الى ترك المتغير في المكان. حل هذا عن طريق:

  printf "%s was here" "\$name"

والتي ستترك $ اسم متغير، بدلا من توسيعها.

وأوصى أيضا تعلم كيفية استخدام مصيدة لصيد الإشارات .. والاستفادة من تلك معالجات كرمز النمطي. حسنه الألباني في تشغيل البرنامج النصي لإبطاء مع SIGUSR1 بسيط هو مفيد جدا:)

ومعظم البرامج الجديدة التي أنا أكتب (والتي هي أداة سطر الأمر / المنحى) تبدأ مخطوطات قذيفة، طريقة رائعة لالنموذج الأولي أدوات UNIX.

وقد ترغب أيضا في SHC قذيفة مترجم النصي، التحقق من ذلك هنا .

وهذا هو رأس يمكنني استخدام لبلدي شيل (باش أو KSH). وهو man نظرة على حد سواء، ويتم استخدامها لعرض استخدام () كذلك.

#!/bin/ksh
#================================================================
# HEADER
#================================================================
#% SYNOPSIS
#+    ${SCRIPT_NAME} [-hv] [-o[file]] args ...
#%
#% DESCRIPTION
#%    This is a script template
#%    to start any good shell script.
#%
#% OPTIONS
#%    -o [file], --output=[file]    Set log file (default=/dev/null)
#%                                  use DEFAULT keyword to autoname file
#%                                  The default value is /dev/null.
#%    -t, --timelog                 Add timestamp to log ("+%y/%m/%d@%H:%M:%S")
#%    -x, --ignorelock              Ignore if lock file exists
#%    -h, --help                    Print this help
#%    -v, --version                 Print script information
#%
#% EXAMPLES
#%    ${SCRIPT_NAME} -o DEFAULT arg1 arg2
#%
#================================================================
#- IMPLEMENTATION
#-    version         ${SCRIPT_NAME} (www.uxora.com) 0.0.4
#-    author          Michel VONGVILAY
#-    copyright       Copyright (c) http://www.uxora.com
#-    license         GNU General Public License
#-    script_id       12345
#-
#================================================================
#  HISTORY
#     2015/03/01 : mvongvilay : Script creation
#     2015/04/01 : mvongvilay : Add long options and improvements
# 
#================================================================
#  DEBUG OPTION
#    set -n  # Uncomment to check your syntax, without execution.
#    set -x  # Uncomment to debug this shell script
#
#================================================================
# END_OF_HEADER
#================================================================

وهنا هو وظائف استخدام للذهاب مع:

  #== needed variables ==#
SCRIPT_HEADSIZE=$(head -200 ${0} |grep -n "^# END_OF_HEADER" | cut -f1 -d:)
SCRIPT_NAME="$(basename ${0})"

  #== usage functions ==#
usage() { printf "Usage: "; head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#+" | sed -e "s/^#+[ ]*//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g" ; }
usagefull() { head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#[%+-]" | sed -e "s/^#[%+-]//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g" ; }
scriptinfo() { head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#-" | sed -e "s/^#-//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g"; }

وهنا هو ما يجب على:

# Display help
$ ./template.sh --help

    SYNOPSIS
    template.sh [-hv] [-o[file]] args ...

    DESCRIPTION
    This is a script template
    to start any good shell script.

    OPTIONS
    -o [file], --output=[file]    Set log file (default=/dev/null)
    use DEFAULT keyword to autoname file
    The default value is /dev/null.
    -t, --timelog                 Add timestamp to log ("+%y/%m/%d@%H:%M:%S")
    -x, --ignorelock              Ignore if lock file exists
    -h, --help                    Print this help
    -v, --version                 Print script information

    EXAMPLES
    template.sh -o DEFAULT arg1 arg2

    IMPLEMENTATION
    version         template.sh (www.uxora.com) 0.0.4
    author          Michel VONGVILAY
    copyright       Copyright (c) http://www.uxora.com
    license         GNU General Public License
    script_id       12345

# Display version info
$ ./template.sh -v

    IMPLEMENTATION
    version         template.sh (www.uxora.com) 0.0.4
    author          Michel VONGVILAY
    copyright       Copyright (c) http://www.uxora.com
    license         GNU General Public License
    script_id       12345

ويمكنك الحصول على القالب النصي الكامل هنا: HTTP: / /www.uxora.com/unix/shell-script/18-shell-script-template

وتمكين الكشف عن خطأ يجعل من الاسهل بكثير للكشف عن المشاكل في وقت مبكر النصي:

set -o errexit

والخروج النصي على الخطأ الأول. وبهذه الطريقة يمكنك تجنب المستمر على أن تفعل شيئا التي تعتمد على شيء في البرنامج النصي في وقت سابق، وربما تنتهي مع بعض الدول نظام غريبة.

set -o nounset

والمراجع علاج للمتغيرات ضبطه على أنها أخطاء. مهم جدا لتجنب الأشياء تشغيل مثل rm -you_know_what "$var/" مع $var ضبطه. إذا كنت تعرف أن المتغير يمكن أن يكون ضبطه، وهذا هو الوضع الآمن، يمكنك استخدام ${var-value} لاستخدام قيمة مختلفة اذا كان ضبطه أو ${var:-value} لاستخدام قيمة مختلفة اذا كان ضبطه <م> أو فارغة.

set -o noclobber

من السهل أن نقع في خطأ إدخال > حيث كنت تعني لادخال <، والكتابة بعض الملفات التي من المفترض أن تقرأ. إذا كنت بحاجة إلى هزم ملف في السيناريو الخاص بك، يمكنك تعطيل هذا من قبل خط ذات الصلة، وتمكينه مرة أخرى بعد ذلك.

set -o pipefail

استخدم أول غير صفرية رمز إنهاء (إن وجدت) من مجموعة القيادة عبر الأنابيب كما رمز الخروج من مجموعة كاملة من الأوامر. وهذا يجعل من الأسهل لتصحيح الأنابيب الأوامر.

shopt -s nullglob

وتجنب أن يتم تفسير غلوب /foo/* بك حرفيا إذا كان هناك أية ملفات مطابقة هذا التعبير.

ويمكنك الجمع بين كل هذه في خطين:

set -o errexit -o nounset -o noclobber -o pipefail
shopt -s nullglob

والقالب باش بلدي هي على النحو التالي (تعيين في بلدي همة التكوين ):

#!/bin/bash

## DESCRIPTION: 

## AUTHOR: $USER_FULLNAME

declare -r SCRIPT_NAME=$(basename "$BASH_SOURCE" .sh)

## exit the shell(default status code: 1) after printing the message to stderr
bail() {
    echo -ne "$1" >&2
    exit ${2-1}
} 

## help message
declare -r HELP_MSG="Usage: $SCRIPT_NAME [OPTION]... [ARG]...
  -h    display this help and exit
"

## print the usage and exit the shell(default status code: 2)
usage() {
    declare status=2
    if [[ "$1" =~ ^[0-9]+$ ]]; then
        status=$1
        shift
    fi
    bail "${1}$HELP_MSG" $status
}

while getopts ":h" opt; do
    case $opt in
        h)
            usage 0
            ;;
        \?)
            usage "Invalid option: -$OPTARG \n"
            ;;
    esac
done

shift $(($OPTIND - 1))
[[ "$#" -lt 1 ]] && usage "Too few arguments\n"

#==========MAIN CODE BELOW==========

أود أن أقترح

#!/bin/ksh

و هذا الأمر.الوزن الثقيل كتلة التعليقات شل النصية ؟ أحصل على نرفزة.

الاقتراحات:

  1. وينبغي أن تكون الوثائق أو البيانات أو رمز, لا تعليقات.على الأقل usage() وظيفة.إلقاء نظرة على كيف ksh وغيرها من AST أدوات الوثيقة نفسها مع الرجل الخيارات على كل أمر.(لا يمكن أن الرابط لأن الموقع هو أسفل.)

  2. تعلن المتغيرات المحلية مع typeset.هذا ما يفعل.لا حاجة سيئة يؤكد.

وما يمكنك القيام به هو جعل السيناريو الذي يخلق رأس السيناريو وويكون ذلك السيارات مفتوحة في محرر المفضلة لديك. رأيت الرجل يفعل ذلك في هذا الموقع:

<وأ href = "http://code.activestate.com/recipes/577862-bash-script-to-create-a-header-for-bash-scripts/؟in=lang-bash" يختلط = " نوفولو "> http://code.activestate.com/recipes/577862-bash-script-to-create-a-header-for-bash-scripts/؟in=lang-bash

#!/bin/bash -       
#title           :mkscript.sh
#description     :This script will make a header for a bash script.
#author          :your_name_here
#date            :20110831
#version         :0.3    
#usage           :bash mkscript.sh
#notes           :Vim and Emacs are needed to use this script.
#bash_version    :4.1.5(1)-release
#===============================================================================

وعموما، لدي بعض الاتفاقيات أود أن التمسك لكل النصي وأنا أكتب. أنا أكتب كل النصوص مع افتراض أن الآخرين قد قراءتها.

وأبدأ كل النصي مع رأس بلدي،

#!/bin/bash
# [ID LINE]
##
## FILE: [Filename]
##
## DESCRIPTION: [Description]
##
## AUTHOR: [Author]
##
## DATE: [XX_XX_XXXX.XX_XX_XX]
## 
## VERSION: [Version]
##
## USAGE: [Usage]
##

وأنا استخدم هذا الشكل التاريخ، لتسهيل البقرى / البحث. I استخدام '[' تستعد للإشارة إلى النص الناس بحاجة إلى إدخال أنفسهم. إذا كانت تحدث خارج تعليق، وأنا أحاول أن بدء لهم '# ['. وبهذه الطريقة اذا كان شخص ما يلصق عليها كما هي، فإنه لن يكون مخطئا لإدخال أو أمر الاختبار. تحقق من المقطع استخدام على صفحة الرجل، لنرى هذا النمط كمثال على ذلك.

وعندما أريد التعليق الخروج سطر من التعليمات البرمجية، وأنا استخدم واحد '#'. عندما أقوم تعليق كملاحظة، يمكنني استخدام مزدوج '##'. يستخدم /etc/nanorc تلك الاتفاقية أيضا. أجد أنه من المفيد، للتمييز التعليق الذي تم اختياره عدم تنفيذ حكم الإعدام. الآيات تعليق الذي تم إنشاؤه كملاحظة.

وجميع المتغيرات قذيفة بلدي، وأنا أفضل أن تفعل في CAPS. وأنا أحاول أن تبقي بين 4-8 حرفا، إلا بالقدر اللازم. وتتعلق هذه الأسماء، على أفضل وجه ممكن، مع استخدامها.

وأنا أيضا دائما الخروج مع 0 في حال نجاحها، أو 1 عن الأخطاء. إذا كان السيناريو لديها العديد من أنواع مختلفة من الأخطاء (وسوف يساعد فعلا شخص ما، أو يمكن أن تستخدم في بعض التعليمات البرمجية في بعض الطريق)، وأود أن اختيار تسلسل وثقت أكثر من 1. بشكل عام، لا يتم فرض رموز الإنهاء كما بدقة في العالم * لا شىء. للأسف لم يسبق لي أن وجدت مخطط رقم عامة جيدة.

وأود أن معالجة الحجج بالطريقة القياسية. أنا أفضل دائما getopts، لgetopt. أنا لم تفعل بعض الإختراق مع الأوامر 'قراءة' وإذا كانت تصريحات. أود أيضا أن استخدام عبارة الحالة، لتجنب المحاذير المتداخلة. يمكنني استخدام برنامج نصي ترجمة لخيارات طويلة، لذلك --help يعني -h لgetopts. أنا أكتب كل البرامج النصية في أي باش (إذا كانت مقبولة) أو ش عام.

وI NEVER استخدام باش تفسير الرموز (أو أي رمز تفسيره) في أسماء الملفات، أو أي اسم لهذه المسألة. على وجه التحديد ... " '` $ & # * () {} [] -، وأنا استخدم _ للمساحات

وتذكر، وهذه هي الاتفاقيات فقط. أفضل الممارسات، والخشنة، ولكن في بعض الأحيان كنت اضطر خارج الخطوط. والأكثر أهمية هو أن تكون متسقة عبر وضمن المشاريع الخاصة بك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top