Шаблоны сценариев оболочки

Что бы вы посоветовали создать хороший шаблон сценария bash / ksh в качестве стандарта для всех вновь создаваемых сценариев?

Я обычно начинаю (после строки #!) с закомментированного заголовка с именем файла, синопсисом, использованием, возвращаемыми значениями, автором (ами), журналом изменений и помещаюсь в строки из 80 символов.

Все строки документации я начинаю с двойных хеш-символов ##, чтобы я мог легко их найти, а имена локальных переменных начинаются с символа «__».

Какие-нибудь другие лучшие практики? Советы? Соглашения об именах? А как насчет кодов возврата?

Комментарии по контролю версий: мы используем SVN, но у другого отдела на предприятии есть отдельное репо, и это их скрипт. Как мне узнать, с кем связаться с Q, если нет информации @author? Использование записей, похожих на javadocs, имеет некоторые достоинства даже в контексте оболочки, IMHO, но я могу ошибаться.

Авторы)? Журнал изменений? Получите систему контроля версий!

derobert 10.01.2009 09:04

Я не уверен, что использование префикса __ для имен локальных переменных полезно.

Jonathan Leffler 01.09.2018 10:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
25
2
47 482
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Я бы предложил

#!/bin/ksh

вот и все. Тяжелые блочные комментарии для сценариев оболочки? Я получаю нервное расстройство.

Предложения:

  1. Документация должна быть данными или кодом, а не комментариями. По крайней мере, функция usage(). Посмотрите, как ksh и другие инструменты AST документируют себя с помощью параметра --man для каждой команды. (Невозможно установить ссылку, потому что веб-сайт не работает.)

  2. Объявите локальные переменные с помощью typeset. Вот для чего это нужно. Нет необходимости в неприятных подчеркиваниях.

Ответ принят как подходящий

Я бы расширил ответ Нормана до 6 строк, и последняя из них пуста:

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

Третья строка представляет собой идентификационную строку для контроля версий - на самом деле это гибрид с маркером SCCS '@(#)', который может быть идентифицирован программой (SCCS) what, и строкой версии RCS, которая расширяется, когда файл помещается в RCS, VCS по умолчанию, который я использую для личного пользования. Программа RCS ident принимает расширенную форму $Id$, которая может выглядеть как $Id: mkscript.sh,v 2.3 2005/05/20 21:06:35 jleffler Exp $. Пятая строка напоминает мне, что сценарий должен иметь описание своего назначения вверху; Я заменяю слово фактическим описанием скрипта (например, поэтому после него нет двоеточия).

После этого для сценария оболочки по сути нет ничего стандартного. Есть стандартные фрагменты, которые появляются, но не стандартные фрагменты, которые появляются в каждом скрипте. (Мое обсуждение предполагает, что сценарии написаны в нотациях оболочки Bourne, Korn или POSIX (Bash). Есть отдельное обсуждение того, почему кто-то, помещающий производную C Shell после сигилы #!, живет во грехе.)

Например, этот код появляется в некоторой форме или форме всякий раз, когда скрипт создает промежуточные (временные) файлы:

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

Первая строка выбирает временный каталог, по умолчанию это / tmp, если пользователь не указал альтернативу ($ 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, так и не-GNU версии программ, и я хочу иметь возможность выбирать, какую из них использовать. Поэтому многие из моих скриптов используют такие переменные, как:

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

И затем, когда мне нужно вызвать Perl или sed, сценарий использует $PERL или $SED. Это помогает мне, когда что-то ведет себя по-другому - я могу выбрать рабочую версию - или во время разработки сценария (я могу добавить в команду дополнительные параметры только для отладки, не изменяя сценарий). (Для получения информации о ${VAR:=value} и соответствующих обозначениях см. Расширение параметров оболочки.)

Привет, @Jonathan, что такое обозначение ": $ {VAR: = file}"? заранее спасибо

tmow 30.03.2012 18:37

@tmow: Обозначение ${VAR:=file} означает, что если для $VAR задано непустое значение, используйте это значение, но если $VAR не задан или установлен в пустую строку, используйте значение file и установите для $VAR это значение. . Итак, это немного похоже (но намного короче): [ -z "$VAR" ] && VAR=file; echo $VAR.

Jonathan Leffler 31.03.2012 05:59

спасибо большое, это действительно полезно !!!

tmow 04.04.2012 16:17

Любой код, который будет выпущен в свет, должен иметь следующий короткий заголовок:

# Script to turn lead into gold
# Copyright (C) 2009 Ima Hacker ([email protected])
# Permission to copy and modify is granted under the foo license
# Last revised 1/1/2009

Ведение журнала изменений в заголовках кода - это возврат к тому времени, когда системы контроля версий были ужасно неудобными. Дата последнего изменения показывает кому-то, сколько лет скрипту.

Если вы собираетесь полагаться на bashisms, используйте #! / Bin / bash, а не / bin / sh, поскольку sh - это вызов POSIX любой оболочки. Даже если / bin / sh указывает на bash, многие функции будут отключены, если вы запустите его через / bin / sh. Большинство дистрибутивов Linux не принимают сценарии, основанные на башизмах, стараются быть переносимыми.

Когда дело доходит до наследования чужих скриптов, я обнаружил, что люди, как правило, много комментируют там, где это не нужно (например, # loop over $var), и очень спорадически там, где необходимы комментарии находятся (например, сверхдлинный однострочный Perl или выполнение JVM с десятками аргументы). Это вообще не является уникальным явлением для сценариев оболочки, это проблема многих устоявшихся баз кода, но особенно неприятно для сценариев. Я не знаю, что делает /bin/foo -- {mile long list of arguments}, глядя на него, но я знаю конструкции написания сценария. Также очень приветствуются комментарии, когда вы делаете что-то, что на первый взгляд выглядит немного чокнутым.

Некоторым оболочкам не нравится получать типизированные «локальные» переменные. Я считаю, что по сей день Busybox (обычная спасательная оболочка) является одним из них. Вместо этого сделайте GLOBALS_OBVIOUS, его намного легче читать, особенно при отладке через / bin / sh -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 
}

Единственный раз, когда я использую обычные if / then / else, - это если есть else-if, чтобы добавить их.

Ужасно безумный пример очень хорошего переносимого шелл-кода можно изучить, просто просмотрев сценарий 'configure' в большинстве бесплатных программных пакетов, использующих autoconf. Я говорю безумие, потому что это 6300 строк кода, который обслуживает каждую известную человечеству систему, имеющую UNIX-подобную оболочку. Вы не хотите такого раздувания, но интересно изучить некоторые из различных хаков переносимости внутри ... например, быть милым с теми, кто может указать / bin / sh на zsh :)

Единственный другой совет, который я могу дать, - это следить за своим расширением в документации, т.е.

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

... расширяет $ name, когда вы, вероятно, захотите оставить переменную на месте. Решите это с помощью:

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

который оставит $ name как переменную, а не расширит ее.

Я также настоятельно рекомендую научиться использовать trap для перехвата сигналов ... и использовать эти обработчики как шаблонный код. Сказать работающему скрипту замедлиться с помощью простого SIGUSR1 очень удобно :)

Большинство новых программ, которые я пишу (которые ориентированы на инструменты / командную строку), начинаются как сценарии оболочки, это отличный способ прототипировать инструменты UNIX.

Вам также может понравиться компилятор сценария оболочки SHC, посмотри здесь.

Если вы не хотите, чтобы здесь расширялись документы, используйте << 'EOF' для подавления раскрытия. Используйте обратную косую черту только тогда, когда вы хотите, чтобы некоторые элементы были расширены, а некоторые - не расширены.

Jonathan Leffler 10.01.2009 21:48

Есть миллион причин, по которым кто-то может захотеть добавить комментарии к сценарию оболочки. Ужасный совет - говорить их глупо.

Dan Grahn 01.01.2021 14:59

@DanGrahn Ух ты, 2009 год, я не всегда хорошо объяснял то, что я хотел сказать :) Я не хотел говорить людям, что все комментарии были глупыми, а скорее об их отсутствии о вещах, которые трудно понять. чтение кода среди множества других комментируемых вещей (например, «цикл здесь»). Отредактировано, лучше?

Tim Post 02.01.2021 21:49

@TimPost Намного лучше! Извините за мертвую стойку, я не осознавал, что она такая старая. ТБХ, я могу сосчитать по пальцам, сколько раз я смотрел код и говорил «слишком много комментариев».

Dan Grahn 04.01.2021 14:54

@DanGrahn Я не думаю, что есть такая вещь, как комментарий кода Плохо (если, конечно, он не вводит в заблуждение), но обилие комментариев вокруг очень очевидного и заметное отсутствие комментариев вокруг того, что не очень очевидно, было раздражающей темой, когда DevOps в основном становился вещью. Вот где был мой мозг, когда я это писал. Мне нравятся возможности, которые возвращают меня к старым ответам вроде этого :)

Tim Post 06.01.2021 19:35

Как правило, у меня есть несколько соглашений, которых я придерживаюсь при написании каждого сценария. Я пишу все сценарии с предположением, что их могут прочитать другие люди.

Я начинаю каждый скрипт с заголовка,

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

Я использую этот формат даты, чтобы упростить поиск с помощью grep / поиска. Я использую фигурные скобки "[" для обозначения текста, который люди должны вводить сами. если они возникают вне комментария, я стараюсь начинать их с '# ['. Таким образом, если кто-то вставит их как есть, это не будет ошибочно принято за ввод или тестовую команду. Проверьте раздел использования на странице руководства, чтобы увидеть этот стиль в качестве примера.

Когда я хочу закомментировать строку кода, я использую один символ "#". Когда я пишу комментарий как примечание, я использую двойной знак «##». /etc/nanorc также использует это соглашение. Я считаю полезным выделить комментарий, который был выбран не к исполнению; стихает комментарий, созданный как примечание.

Все мои переменные оболочки я предпочитаю использовать ЗАГЛАВНЫМИ БУКВАМИ. Я стараюсь использовать от 4 до 8 символов, если не требуется иное. Имена как можно лучше связаны с их использованием.

Я также всегда выхожу с 0 в случае успеха или 1 в случае ошибок. Если в сценарии есть много разных типов ошибок (и он действительно может кому-то помочь или может быть использован в каком-то коде каким-либо образом), я бы выбрал задокументированную последовательность, а не 1. В общем, коды выхода не так строго соблюдаются в мире * nix. К сожалению, я так и не нашел хорошей общей схемы счисления.

Мне нравится обрабатывать аргументы стандартным способом. Я всегда предпочитаю getopts, чтобы getopt. Я никогда не занимаюсь хакерскими операциями с командами чтения и операторами if. Мне также нравится использовать оператор case, чтобы избежать вложенных if. Я использую сценарий перевода для длинных параметров, поэтому --help означает -h для getopts. Я пишу все сценарии либо на bash (если возможно), либо на общем языке sh.

Я НИКОГДА не использую интерпретируемые символы bash (или любые интерпретируемые символы) в именах файлов или в любом другом имени в этом отношении. в частности ... "'` $ & * # () {} [] -, я использую _ вместо пробелов.

Помните, это всего лишь условности. Лучшая практика, грубо говоря, но иногда вы вынуждены выйти за рамки. Самое важное - быть последовательными в своих проектах и ​​внутри них.

Я использую первый набор ## строк для документации по использованию. Не могу вспомнить, где впервые это увидел.

#!/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.
}

Функция usage () grepping скрипта сначала выглядит круто, но она терпит неудачу, если скрипт выполняет cd в любом месте, а $0 не является абсолютным именем файла. Я бы выбрал функцию usage (), чтобы фактически выводить сообщение об использовании / printf / cat.

Jens 27.10.2011 23:03

Вы можете определить абсолютный путь к сценарию и сохранить его в переменной. Было бы неплохо, если бы информация об использовании была вверху в комментариях. Если вы это сделаете, то нажатие на скрипт для вывода информации из комментариев сделает код СУХИМ.

toxalot 22.03.2014 00:42

@Jens вряд ли нужно вызывать cd перед вызовом usage / help, также альтернатива, которую вы предлагаете, просто плохая. Я согласен с toxalot, приятно просто просмотреть текст программы и увидеть в виде простого текста краткое изложение того, что она делает.

André Werlang 06.04.2020 00:26

Что вы можете сделать, так это создать сценарий, который создает заголовок для сценария и автоматически открывает его в вашем любимом редакторе. Я видел, как парень делал это на этом сайте:

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
#===============================================================================

Включение обнаружения ошибок значительно упрощает обнаружение проблем в скрипте на раннем этапе:

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

Мой шаблон bash выглядит следующим образом (установлен в моем конфигурация vim):

#!/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==========

Это заголовок, который я использую для своей оболочки сценария (bash или ksh). Это похоже на man, и он также используется для отображения usage ().

#!/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

Ваше сообщение не включает весь ваш шаблон, и ваш сайт помещает код за «стеной социальных сетей», это следует рассматривать как плохое поведение.

Hultner 27.04.2017 17:48

Другие вопросы по теме