Strongbash Коменты

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

корзина:strongbash_коменты [10.03.2018 15:59]
admin [strongbash022 TODO]
корзина:strongbash_коменты [20.05.2019 15:18]
Строка 1: Строка 1:
-===== Соглашение по строгому bash ===== 
  
-===== strongbash001 ===== 
-**Обязательно должен быть выполнен crab_indent**. 
-<hidden Почему...>​ 
-  - indent делает код более читаемым 
-  - использование indent позволяет обнаруживать ошибки 
-</​hidden>​ 
-<hidden Пример...>​ 
-Конструкция **if-then** располагаются в одной строке.\\ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-if [ "​$EUID"​ -ne "​0"​ ]; then 
-      echo "​Please run as root" 
-fi 
-</​code>​ 
- 
- 
-Фигурная скобка **"​{"​** для определния тела функции должна быть в одной строке с функцией.\\ 
-После переноса строки добавляем **<​Tab>​**.\\ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-myfunc1() { 
-      commands... 
-} 
-</​code>​ 
- 
-Объявление функции без ключевого слова **function**.\\ 
-Ключевое слово function было введено в ksh.\\ 
-POSIX стандартизирует только синтаксис funcname().\\ 
-Код в скобках с отступами.\\ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-myfunc1() { 
-      echo "Hello world" 
-} 
-</​code>​ 
- 
-<color #​ed1c24>​Плохо:</​color>​ 
-<code bash> 
-function myfunc1 { 
-      echo "Hello world" 
-} 
-</​code>​ 
- 
-Инструкция **case ** без оступов:​\\ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-case "​$variable"​ in 
-"​$condition1"​ ) 
-      command... 
-      ;; 
- 
-"​$condition2"​ ) 
-      command... 
-      ;; 
- 
-esac 
-</​code>​\\ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-#​!/​usr/​bin/​env bash 
- 
-set -euEo pipefail 
- 
-func1(){ 
-        grep '​zzz'​ /​tmp/​temp1.tmp | cat \ 
-                | grep zza \ 
-                && echo zzz || echo aaa 
-        return 0 
-} 
- 
-if func1; then 
-        echo true 
-else 
-        echo false 
-fi 
- 
-( 
-        cd /tmp/ 
-        ls 
-) \ 
-| ( 
-        while read t; do 
-                echo $t 
-        done 
-  ) 
- 
-case "​${2:​-bash}"​ in 
-bash) 
-        echo bash 
-        ;; 
-*) 
-        echo "not supported yet. plz add new style" 
-        ;; 
-esac 
- 
-exit 0 
-</​code>​ 
-</​hidden>​ 
- 
-===== strongbash002 ===== 
-**Должен быть установлен set -euEo pipefail или include ::​carbon.sys** \\ 
-<WRAP center round important>​ВНИМАНИЕ set -eu это самое главное правило,​ оно дает режим strong.\\ 
-Позволяет отлавливать и исключать неявное и непредсказуемое поведение программы,​ а также быстрей отлаживать.\\ 
-</​WRAP>​ 
-<WRAP center round important>​ 
-ОЧЕНЬ БОЛЬШОЕ ВНИМАНИЕ set -eu используется для того, чтобы отловить неизвестные **будущие** ошибки программы и не дать ей выполняться далее.\\ 
-set -eu **не должен** использоваться для реализации какой либо логики основного алгоритма.\\ 
-</​WRAP>​ 
-<hidden Что включает...>​ 
-set -e падать если есть необработанные ошибки,​ а точнее необработанный код возврата.\\ 
-set -u падать если используется неинициализированная переменная.\\ 
-set -o pipefail ​ падать в ERR если в одной из пайп команд произошла ошибка.\\ 
-set -E наследовать trap в функциях.\\ 
-</​hidden>​ 
-<hidden Как не надо делать...>​ 
-Todo вынести в отдельное правило\\ 
-<color #​ed1c24>​Плохо делать ассерты вида:</​color>​\\ 
-<code bash> 
-[ $# = 3 ] 
-</​code>​ 
-<color #​22b14c>​Хорошо явно отлавливать и писать текстом пользователю о **заранее** известных ошибках:</​color>​\\ 
-<code bash> 
-[ $# != 3 ] && { echo '​Укажите 3 параметра';​ exit 1; } 
-</​code>​ 
-<color #​ed1c24>​Плохо **пытаться** использовать возможности set -e для формирования кода возврата функций:</​color>​ 
-<code bash> 
-set -e 
-func1(){ 
-        grep qqq /​tmp/​myqqq.txt ​ 
-        # ^^^ не надо надеяться на то, что здесь упадет и функция вернет не ноль, здесь не остановится выполнение функции. 
-        # такой подход технически невозможен ни с ни без set -e 
-        return 0 
-} 
-### это работать не будет 
-func1 && echo "qqq найден"​ 
-</​code>​ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-func1(){ 
-        set -e ### требуется указать еще раз чтоб работало ret=$( func1 ) 
-        grep qqq /​tmp/​myqqq.txt && echo TRUE || echo FALSE 
-        return 0 
-} 
-ret="​$(func1)"​ 
-[ "​$ret"​ = "​TRUE"​ ] && echo "qqq найден"​ 
-</​code>​ 
-</​hidden>​ 
-<hidden Проблемы и решения set -euEo pipefail...>​ 
-<WRAP center round info> 
-set -euEo pipefail дает огромную пользу для предсказуемости работы и отладки,​ 
-но есть небольшие побочки,​ которые легко решаются.\\ 
-</​WRAP>​ 
-<color #​ed1c24>​Проблема pipefail иногда мешает делать grep:</​color>​\\ 
-<code bash> 
-set -euEo pipefail 
-# grep myssh Упадет если нет слова myssh, хотя мы может этого не хотели,​ а хотели пустой файл 
-ps aux | grep -v grep | grep myssh >/​tmp/​tmp1; ​ echo ret=$?; 
-</​code> ​ 
-<color #​22b14c>​Решение,​ добавить || true :</​color>​ 
-<code bash> 
-set -euEo pipefail ​ 
-ps aux | grep -v grep | grep myssh >/​tmp/​tmp1 || true;  echo ret=$?; 
-</​code> ​ 
-\\ 
-<color #​ed1c24>​Проблема,​ если мы вызываем функцию и анализируем ее код возврата\\ 
-в ней перестает работать set -e :</​color>​\\ 
-<code bash> 
-set -e 
-check_is_oversized(){ 
-       # set -e здесь бесполезно добавлять 
-       [ `stat -c %s $1` -gt 1000 ] && return 1 # если программа stat упадет?​ то ошибки не будет тк set -e здесь выключен уже 
-       # в итоге вернется return 0 даже если stat упал 
-       ​return 0 
-} 
-check_is_oversized /​tmp34/​11.log && echo "​файл слишком большой"​ ### команда '&&'​ отключит обработку ошибок функции check_is_oversized 
-</​code>​ 
-<color #​22b14c>​Решение,​ можно использовать echo TRUE вместо return 0 :</​color>​\\ 
-<code bash> 
-set -e 
-check_is_oversized(){ 
-       set -e  ### обязательно еще раз тк он снимется при ret=$( check_is_oversized ) 
-       [ `stat -c %s $1` -gt 1000 ] && echo TRUE 
-       echo FALSE 
-       ​return 0 
-} 
-### обязательно через промежуточную переменную иначе тоже set -e потеряется 
-### не будет работать [ "$( check_is_oversized /​tmp34/​11.log )" = TRUE ] 
-ret=$( check_is_oversized /​tmp34/​11.log ) 
-[  "​$ret"​ = TRUE ] && ​ echo "​файл слишком большой"​ 
-### Из минусов такого подхода это запуск сабшела и небольшой оверхед,​ 
-### поэтому при массовых(10000) вызовах ​ функции приходится ее использовать с потерей контроля ошибок и обычным return 
-### или можно использовать глобальную переменную ERRNO= или глобальную FNAME_RET= 
-### или работать процедурно через eval:  funct_search txt1 txt2 rettxt1 ​  ​funct_search () { eval "​$3"​='​$value'​ } 
-</​code>​\\ 
-<color #​ed1c24>​Плохо использовать</​color>​ 
-Такую конструкцию для запуска вложенных функций-команд с отловом кода возврата и без потери set -e, тк не удовлетворяет правилу skill-1 и pl7 
-<code bash> 
-( set +e; (set -e; fun1; ); ret=$?; ); 
-</​code>​ 
-\\ 
-<color #​ed1c24>​Проблема set -u иногда непривычен для входящих параметров:</​color>​\\ 
-<code bash> 
-src=$1 ​  # если $1 не передан,​ то программа упадет 
-</​code>​ 
-<color #​22b14c>​Решение,​ можно использовать default значения переменных:</​color>​ 
-<code bash> 
-echo ${1:​-defaulttxt} 
-</​code>​ 
-<code bash> 
-[ "​${1:​---help}"​ = '​--help'​ ] && { echo '​Example:​ $0 src dst'; exit 0; } 
-</​code>​ 
-Или учитывая правило skill -1 надо делать так:\\ 
-<code bash> 
-[ "​${1:​-}"​ = ''​ -o "​${1:​-}"​ = '​--help'​ ] && { echo '​Example:​ $0 src dst'; exit 0; } 
-или 
-my_src="​${1:​-}"​ 
-</​code>​ 
-</​hidden>​ 
-===== strongbash003 ===== 
- 
-**Нельзя использовать || true в условных выражениях.**\\ 
- 
-<hidden Почему...>​Это миф что без них не работает и все падает при set -e.\\ 
-Все отлично работает,​ если return 0 в конце каждой функции и exit 0 в конце каждого файла.</​hidden>​ 
-<hidden Пример...>​ 
-<color #​ed1c24>​Как не надо делать:</​color>​ 
-<code bash> 
-funct1(){ 
-        [ a = b ] && echo Привет || true 
-} 
-</​code>​ 
-<color #​22b14c>​Как надо делать:</​color>​ 
-<code bash> 
-funct1(){ 
-        [ a = b ] && echo Привет 
-        return 0 
-} 
-</​code>​ 
-</​hidden>​ 
-===== strongbash004 ===== 
- 
-**Нельзя использовать else true в условных выражениях**\\ 
-см strongbash003 
- 
-===== strongbash005 ===== 
-**В конце каждой функции должен быть return 0 или return $ret или exit 0 или exit $ret**\\ 
-<hidden Почему...>​Это обязательно,​ чтобы не передать случайно неявное ​ и нежелаемое значение последнего if, вместо явного.</​hidden>​ 
-<hidden Пример...>​ 
-<color #​ed1c24>​Плохо:</​color>​ 
-<code bash> 
-prepare_text(){ 
-        local text="​${1:​-}"​ 
-        [ "​$text"​ = ""​ ] && echo "​Привет" ​ 
-        ### "​вот здесь мы отловили код возврата и не должны упасть,​ но мы упадем сразу после выхода из функции"​ 
-        ### тк вернется последний код возврата 
-}; 
-arg1=$( prepare_text "​555"​ ) 
-echo $arg1 
-</​code>​ 
- 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-prepare_text(){ 
-        local text="​${1:​-}"​ 
-        [ "​$text"​ = ""​ ] && echo "​Привет" ​ 
-        return 0   ### мы всегда явно задаем,​ что мы хотим вернуть либо return 0 либо return $ret 
-}; 
-arg1=$( prepare_text "​555"​ ) 
-echo $arg1 
-</​code>​ 
-</​hidden>​ 
-===== strongbash006 ===== 
-**В начале каждого файла должен быть echo START и EXAMPLE\\ 
-В конце каждого файла должны быть echo SUCCESS и exit 0 :\\ ** 
-Для продвинутых разработчиков лучше использовать в начале скрипт:​ include ::​carbon.sys 
-<hidden Почему...>​ 
-  - exit 0 для того чтобы избежать случайный код возврата. 
-  - EXAMPLE использования важен, чтобы программа могла жить в будущем и не была выборошена. 
-  - echo START echo SUCCESS делает удобным использование и чтение логов. 
-  - include ::​carbon.sys позволит автоматически деалать echo START echo SUCCESS echo FAIL sys::usage "​$@"​ ### --help EXAMPLE и показывает callstack при падении 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-#!/bin/bash 
-echo "$0 $@ [$$] START" >&2 
-[ "​${1:​---help}"​ = '​--help'​ ] && { echo Example: $0 src dst; exit 0; } 
-cmd1 
-cmd2 
-cmd3 
-echo "$0 $@ [$$] SUCCESS"​ >&2 
-exit 0 
-</​code>​ 
-<color #​22b14c>​Хорошо если много exit 0 в программе</​color>​ 
-<code bash> 
-#!/bin/bash 
-echo "$0 $@ [$$] START" >&2 
-[ "​${1:​---help}"​ = '​--help'​ ] && { echo Example: $0 src dst; exit 0; } 
-ARGV="​$@"​ 
-__exit(){ 
-        local ret=$1 
-        [ "​$ret"​ = 0 ] && echo "$0 $ARGV [$$] SUCCESS"​ >&2 \ 
-                || echo "$0 $ARGV [$$] FAILED"​ >&2 
-        exit $ret 
-} 
- 
-cmd1 
-cmd2 || __exit 0 
-cmd3 
-echo "$0 $@ [$$] SUCCESS"​ >&2 
-exit 0 
-</​code>​ 
- 
-<color #​22b14c>​Хорошо для продвинутых и для карбон софт:</​color>​ 
-<code bash> 
-#!/bin/bash 
-source ::​carbon.sys 
-sys::usage "​$@"​ 
-### --help Example: vm_backup src node2 
-cmd1 
-cmd2 
-cmd3 
-exit 0 
-</​code>​ 
-</​hidden>​ 
- 
-<hidden Решение проблем...>​ 
-<color #​22b14c>​Хорошо для тихих файлов:</​color>​ 
-<code bash> 
-# echo "$0 START">&​2 
-# echo "$0 SUCCESS">&​2 
-</​code>​ 
- 
- 
-<color #​22b14c>​Или для тихих файлов с carbon.sys:</​color>​ 
-<code bash> 
-__SILENT=TRUE 
-source ::​carbon.sys 
-</​code>​ 
-</​hidden>​ 
-===== strongbash007 ===== 
- 
-**В конце каждого файла должен быть exit 0 или для библиотек:​ # exit 0.** 
-<hidden Почему...>​ 
-Мы должны явно задавать все легальные выходы из программы аналогично как с функциями.\\ 
-exit 0 в отличии от exit $ret дополнительно защитит от будущих ошибок при рефакторинге кода.\\ 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​22b14c>​Хорошо</​color>​ 
-<code bash> 
-#!/bin/bash 
-echo "$0 $@ [$$] START" >&2 
-cmd1  
-[ $sz -gt 110 ] && { echo "​Ошибка sz=$sz";​ exit 2; } 
-cmd2 
-cmd3 
-echo "$0 $@ [$$] SUCCESS"​ >&2 
-exit 0 
-</​code>​ 
-<color #​ed1c24>​Плохо exit $ret тк в будущем при рефакторинге может появиться неоднозначности</​color>​ 
-<code bash> 
-#!/bin/bash 
-echo "$0 $@ [$$] START" >&2 
-cmd1  
-[ $sz -gt 110 ] && { echo "​Ошибка sz=$sz";​ exit 2; } 
-cmd2 
-cmd3 || ret=$? 
-echo "$0 $@ [$$] SUCCESS"​ >&2 
-exit $ret 
-</​code>​ 
- 
-<color #​22b14c>​Хорошо. Если Ваш файл должен возвращать разные коды легально,​ то нужно это сделать явно : 
-</​color>​ 
-<code bash> 
-#!/bin/bash 
-echo "$0 $@ [$$] START" >&2 
-cmd1 
-ret=1 
-ret=4 
-ret=2 
-echo "$0 $@ [$$] SUCCESS"​ >&2 
-[ $ret != 0 ] && exit $ret 
-exit 0 
-</​code>​ 
-</​hidden>​ 
- 
-===== strongbash008 ===== 
- 
-**Нужно использовать shebang #!/bin/bash и даже в include**\\ ​ 
-**Не нужно использовать shebang переносимости <​del>#​!/​usr/​bin/​env bash</​del>​** 
-<hidden Почему...>​ 
-1. Позволит проверять include на crab_syntax\\ 
-2. #​!/​usr/​bin/​env не нужно использовать для /bin/bash тк 99,999 ОС linux bash лежит в /bin/bash и только если Вы хотите использовать код на не linux, тогда возможно потребуется /​usr/​bin/​env\\ 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​ed1c24>​Плохо</​color>​ 
-<code bash> 
-#​!/​usr/​bin/​env bash 
-</​code>​ 
-<color #​22b14c>​Хорошо</​color>​ 
-<code bash> 
-#!/bin/bash 
-</​code>​ 
-</​hidden>​ 
-===== strongbash009 ===== 
- 
-**Нельзя использовать команду let.** 
-<hidden Почему...>​ 
-Так как она дает ошибку при переходе через 0, let i=1-1 упадет скрипт. 
-</​hidden>​ 
-<hidden Пример...>​ 
-Плохо: 
-<code bash> 
-let c=a-b 
-</​code>​ 
-Хорошо:​\\ 
-<code bash> 
-c=$((a-b)) 
-</​code>​ 
-</​hidden>​ 
- 
-===== strongbash010 warning TODO ===== 
-**Не рекомендуется использовать переменные,​ особенно глобальные,​ для временных файлов,​ если эта переменная используется менее 5 раз.**\\ 
-<​del>​$TMP_FILE=$( mktemp /​tmp/​tmp_file.XXXX )</​del>​ 
-<hidden Почему...>​ 
-  - Это усложняет чтение кода и понимание кода, файл сам по себе есть переменная и временная ссылка на него редко оправдана.\\ 
-  - Плохо если приходится искать далеко вверху по коду, что это за переменная,​ и что там в этом файле.\\ 
-  - mktmp это тоже плохо так как бессмысленно.\\ 
-  - Имя временного файла должно содержать в себе имя исполняемой программы и ее PID обязательно.\\ 
-</​hidden>​ 
- 
-<hidden Пример...>​ 
-<color #​ed1c24>​Плохо тк используется мало и глобальная переменная:</​color>​ 
-<code bash> 
-$TMP_FILE_CAT_FROM=/​tmp/​${binname}_tmpls.$$ ​ или ​ $TMP_FILE_CAT_FROM=$( mktemp /​tmp/​tmpls.XXXX ) 
-ls /var/lib > $TMP_FILE_CAT_FROM 
-while read f; do 
-        echo $f 
-done < $TMP_FILE_CAT_FROM 
-rm -f $TMP_FILE_CAT_FROM 
-</​code>​ 
-<color #​ed1c24>​Плохо тк используется далеко от объявления и глобальная переменная:</​color>​ 
-<color #​ed1c24>​(Иногда это нормально для временных каталогов)</​color>​ 
-<code bash> 
-$TMP_FILE_CAT_FROM=/​tmp/​${binname}_tmpls.$$ ​ или ​ $TMP_FILE_CAT_FROM=$( mktemp /​tmp/​tmpls.XXXX ) 
-код1 
-код2 
-код3 
-код4 
-код5 
-код6 
-ls /var/lib > $TMP_FILE_CAT_FROM 
-while read f; do 
-        echo $f 
-done < $TMP_FILE_CAT_FROM 
-ls /var/lib > $TMP_FILE_CAT_FROM 
-while read f1; do 
-        echo $f1 
-done < $TMP_FILE_CAT_FROM 
-ls /var/lib > $TMP_FILE_CAT_FROM 
-while read f2; do 
-        echo $f2 
-done < $TMP_FILE_CAT_FROM 
-rm -f $TMP_FILE_CAT_FROM 
-</​code>​ 
- 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-ls /var/lib > /​tmp/​myname_tmpls.$$ 
-        while read f; do 
-echo $f 
-done < /​tmp/​myname_tmpls.$$ 
-rm -f /​tmp/​myname_tmpls.$$ 
-</​code> ​ 
- 
- 
-<color #​22b14c>​Хорошо объявили и сразу используем много раз:</​color>​ 
-<code bash> 
-$tmpls=/​tmp/​${binname}_tmpls.$$ или $tmpls=/​tmp/​${binname}_tmpls.$$.$(RANDOM) или $tmpls=$( mktemp /​tmp/​${binname}_tmpls.$$.XXXX ) 
-ls /var/lib > $tmpls 
-while read f; do 
-        echo $f 
-done < $tmpls 
-echo ls /var/lib2 >  $tmpls 
-cat lilo.conf >  $tmpls 
-if grep ttt $tmpls; then 
-       echo ddd 
-fi 
-rm -f $tmpls 
-</​code>​ 
-</​hidden>​ 
-===== strongbash011 ===== 
-**Максимальный indent вложенность 5**\\ 
-<hidden Почему...>​ 
-Большая вложенность всегда приводит к большой вложенности мысли при чтении кода, это неудобно и приводит к ошибкам.\\ 
-Используйте ранний return или сделайте подфункции,​ или case и тп.\\ 
-Не используйте большие if then else и мозг будет занят 5-ю уровнями вложенности.\\ 
-</​hidden>​ 
- 
- 
-===== strongbash012 ===== 
-**Команды | и || и && при переносе длинных строк** \\ 
-**требуется вынести на следующую строку и поставить tab.** 
-<hidden Почему...>​ 
-Это повышает читаемость кода и делает явным, что был перенос и это продолжение предыдущей строки. 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-cat 123 | grep 123 | sed | cat | grep \ 
-        | while read t; do echo 123; done \ 
-</​code>​ 
-</​hidden>​ 
- 
-===== strongbash013 ===== 
-**Ставьте пробел после #**\\ 
-**Можно используйте без пробелов #}  и  #{ для исправления ошибок crab_indent.** 
- 
-===== strongbash014 ===== 
-**Максимальный размер функции 64 строки,​ а лучше 32.** 
-<hidden Почему...>​ 
-Каждая функция это смысловая единица которая должна помещаться в пару предложений человеческого языка, это правильное нативное удобное для мозга деления на смыслы.\\ 
-</​hidden>​ 
-<hidden Что делать если больше...>​ 
-Выделите подфункции,​ часто вида: 
-<code bash> 
-__fname(){ 
-} 
-</​code>​ 
-При этом не нужно создавать миллиард функций на каждое словосочетание тк любая функция эта новая сущность,​ а плодить сущности плохо.\\ 
-И если функция из 4 строк вызывается один раз, то врядли она нужна.\\ 
-</​hidden>​ 
- 
-===== strongbash015 ===== 
-**Слишком большой линейный файл больше 64 строк, выделите подфункции.** 
-<hidden Почему...>​ 
-Если в файле больше 64 строк, значит однозначно есть команды которые делают похожие вещи и правильней их объединить в функции.\\ 
-</​hidden>​ 
-===== strongbash016 ===== 
- 
-**Уберите конечные space, tab.**\\ 
-**В конце файла должен стоять один enter.**\\ 
- 
-===== strongbash017 ===== 
- 
-**Длина строки должна быть не более 100 символов. Используйте переносы '​\'​** 
-<hidden Почему...>​ 
-Человеческий мозг нормально воспринимает до 7-10 слов в одну ширину строки,​ если больше,​ то нужно делать перенос и желательно в точке новой подкоманды.\\ 
-Не нужно надеяться на встроенные псевдопереносы IDE средств,​ это совсем другое.\\ 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-echo "​aaaaaaaaaaaaaaaaaaaaaa"​\ 
-    "​bbbbbbbbbbbbbbbbbbb"​ 
-или 
-txt="​aaaaaaaaaaaaaaaaaaaaaa"​\ 
-"​bbbbbbbbbbbbbbbbbbb"​ 
-или  ​ 
-echo "​aaaaaaaaaaaaaaaaaaaaaa\ 
-bbbbbbbbbbbbbbbbbbb"​ 
- 
-iptables -t nat -I xge_pre -m addrtype ! --dst-type LOCAL \ 
-        -m set ! --match-set xge_auth_list src \ 
-        -m set ! --match-set xge_auth_list dst -j RETURN 
-</​code>​ 
-</​hidden>​ 
-===== strongbash018 ===== 
- 
-**Поставьте пробел перед символом перенаправления '>'​** 
-<hidden Пример...>​ 
-<code bash> 
-echo "​text"​ > file.txt 
-</​code>​ 
-</​hidden>​ 
- 
-===== strongbash019 ===== 
-**Добавьте пример использования программы echo '​Example:​ myname src dst'** 
-<hidden Пример...>​ 
-<color #​22b14c>​Хорошо:</​color>​ 
-<code bash> 
-[ "​${1:​---help}"​ = '​--help'​ ] && { echo Example: myname src dst; exit 0; } 
-</​code>​ 
-<color #​22b14c>​Хорошо при include ::​carbon.sys</​color>​ 
-<code bash> 
-sys::usage "​$@"​ и  
-### --help Example: ​ myname src dst  
-</​code>​ 
-</​hidden>​ 
-===== strongbash020 TODO ===== 
-**Запрещены функции Log в утилитах**\\ 
-Запрещены любые LOG $(date) в утилитах,​ это можно только в демонах и в кроне 
-<code bash> 
-crab_logger {name_tool} &>>/​var/​log/​name_tool.log 
-crab_exec -t timeout --daemon --log2 -u root --onlyonce --lock {name_tool} &>>/​var/​log/​name_tool.log 
-# не утверждено как именно 
-</​code>​ 
- 
-===== strongbash021 TODO ===== 
-**Запрещено удалять tmp в trap EXIT.**\\ 
-создание временного файла это своего рода with file и его удаление это end with, чтоб было понтяно где он более не нужен аля область работы с файлом. И если файл остался в тмп то это признак,​ что есть ошибка в логике. 
- 
-===== strongbash022 ===== 
-**1. Утилиты должны удалять за собой временные файлы**\\ 
-**2. Запрещено в утилитах передавать результаты через промежуточные файлы. Только errno stdout stderr.** 
-** В исключительных случаях имя файла должно быть в argv или конфиг в argv.**\\ 
-Непонятно как проверять,​ что результаты идут через промежуточные файлы, пока проверяем,​ что чистится /tmp/\\ 
- 
-===== strongbash023 ===== 
-**1. Нужно всегда использовать read <color #​ed1c24>​-r</​color>​ f1 f2 **\\ 
-**2. А для чтения целой строки while <color #​ed1c24>​IFS=<​nowiki>''</​nowiki></​color>​ read -r line; do**\\ 
-<hidden Почему...>​ 
-1. read -r иначе все esc последовательности обработаются,​ это вряд ли Вы хотели.\\ 
-2. IFS=<​nowiki>''</​nowiki>​ иначе начальные пробелы и табы потеряются и строка будет не та, что в оригинале.\\ 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​ed1c24>​Как не надо делать:</​color>​ 
-<code bash> 
-read f1 f2 < /tmp/myfile 
- 
-while read line; do 
-        echo "​$f"​ 
-done < /tmp/myfile 
-</​code>​ 
-<color #​22b14c>​Как надо делать:</​color>​ 
-<code bash> 
-read -r f1 f2 < /tmp/myfile 
-while IFS=''​ read -r line; do 
-        echo "​$f"​ 
-done < /tmp/myfile 
-</​code>​ 
-</​hidden>​ 
- 
-===== strongbash024 ===== 
-** 1. Запрещено rm -rf "/​$dir"​ "​./​$dir"​ "​$dir*"​ "​$dir/​*"​ "​$dir/"​ **\\ 
-** 2. rm -rf  всегда с –one-file-system**\\ ​ 
- 
-<hidden Почему...>​ 
-1. Это приводит к удалению незадуманных файлов если переменная пустая\\ 
-2. При работе с контейнерами и виртуалками,​ очень велик риск удалить их rootfs, а используются они сейчас повсеместно.\\ 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​ed1c24>​Как не надо делать:</​color>​ 
-<code bash> 
-rm -rf "/​$dir"​ 
-rm -rf "​./​$dir"​ 
-rm -rf "​$dir*"​ 
-rm -rf "​$dir/​*"​ 
-rm -rf "​$dir/" ​ 
-</​code>​ 
-<color #​22b14c>​Как надо делать:</​color>​ 
-<code bash> 
-rm -rf -one-file-system "​$dir"​ 
-rm -rf -one-file-system "/​var/​cache/​mydir/​*"​ 
-</​code>​ 
-</​hidden>​ 
-===== strongbash025 ===== 
-**"​do"​ и "​then"​ НЕ делаем c новой строки**\\ 
-<hidden Почему...>​В большинстве языков принято в одной строке поэтому большинству так привычней.\\ 
-</​hidden>​ 
-<hidden Пример...>​ 
-<color #​ed1c24>​Как не надо делать:</​color>​ 
-<code bash> 
-if true; 
-then 
-        echo true 
-fi 
-while read t; 
-do 
-        echo $t 
-done 
-</​code>​ 
-<color #​22b14c>​Как надо делать:</​color>​ 
-<code bash> 
-if true; then 
-        echo true 
-fi 
-while read t; do 
-        echo $t 
-done 
-</​code>​ 
-</​hidden>​ 
-===== strongbash026 ===== 
-**Нельзя использовать голые скобки для assert и тп [ a = b ]**\\ 
- 
-<hidden Почему...>​Это противоречит явности кода и человекочитаемости ошибок.\\ 
-Это использование set -e для основной логики,​ что запрещено.\\ 
-</​hidden>​\\ 
-<hidden Пример...>​ 
-<color #​ed1c24>​Как не надо делать:</​color>​ 
-<code bash> 
-[ "​$fname"​ = ""​ ] 
-</​code>​ 
-<color #​22b14c>​Как надо делать:</​color>​ 
-<code bash> 
-[ "​$fname"​ = ""​ ] && { echo '​Укажите имя файла';​ exit 1; } 
-</​code>​ 
-<color #​22b14c>​Как надо делать:</​color>​ 
-<code bash> 
-# Или не проверять все подряд,​ тк все на свете проверить анрил, само упадет по set -e 
-</​code>​ 
-</​hidden>​ 
-===== strongbash027 TODO ===== 
-нельзя использовать конструкции вида [ a = b ] || cmd1 кроме утвержденного сахара\\ 
- 
-===== strongbash028 only warning TODO ===== 
-**Стараться не использовать cmd1 || cmd2 || cmd3** ​ лучше проверять окружение и вызвать сразу нужное If centos if ubintu if dir \\ 
-**Пример такой сахар разрешен,​ как разрешать отдельные ошибки команд не заглушая остальные**\\ 
-<code bash> 
-Если бы не существовало команды git status 
-error=$( git commit -m '​qqqqqqqqqqq'​ 2>&1 ) \ 
-        || echo "​$error"​ | grep -qm1 '​nothing to commit'​ \ 
-        || { echo  "​$error";​ exit 1; } 
-или 
-error=$( git commit -m '​qqqqqqqqqqq'​ 2>&1 ) \ 
-        || [[ $error != *"​nothing to commit"​* ]] && { echo  "​$error";​ exit 1; } 
-</​code>​ 
-**НО правильнее** 
-<code bash> 
-if ! git status | grep -qm1 '​nothing to commit';​ then 
-       git commit -m '​qqqqqqqqqqq'​ 
-fi 
-</​code>​ 
- 
-===== strongbash029 ===== 
- 
-**Если мы берем stdout от функции мы обязаны прописать в первой строке set -e тк он снимается** 
-===== strongbash030 ===== 
-**Нельзя вызывать функцию внутри if fname и fname&&​ и fname||** 
- 
-===== TODO добавить в инструкцию как программировать на баше ===== 
-**TODO** Описать виды функций __funct funct и виды переменных ARG CONF GLOBAL local и namespace сабшелы\\ 
-**TODO** 
-В файл примера 
-<code bash> 
-iptables -t nat -I xge_pre -m addrtype ! --dst-type LOCAL \ 
-        -m set ! --match-set xge_auth_list src \ 
-        -m set ! --match-set xge_auth_list dst -j RETURN 
-</​code>​ 
- 
-Добавить в описание правил что grep -qm1 может уронить левую часть если это долгая команда и отгрепается первая строка пример 
-<code bash> 
- ( set -euEo pipefail; for((i=0;​i<​10;​i++));​ do echo q; sleep 1; done | grep  -q q ); echo $? 
-</​code>​ 
- 
-Добавить в описание 
-для всего есть подходящие инструменты,​ bash отличный скриптовый язык, позволяющий делать мощные программы написав немного кода по вызову готовых утилит. 
-И при этом этот код легко сопровождать и разбирать потом без программиста,​ админам и саппорту. 
-Есть куча кейсов где программы на баше в 10 раз меньше,​ чем на питоне при этом надежней и написана за гораздо меньшее время. 
- 
-~~DISCUSSION~~