Пользователь
0,0
рейтинг
17 декабря 2008 в 16:36

Администрирование → Основы BASH. Часть 1 tutorial

Безусловно, все те кто общается с ОС Linux хоть раз да имели дело(во всяком случае слышали точно) с командной оболочкой BASH. Но BASH не только командная оболочка, это еще и превосходный скриптовый язык программирования.
Цель этой статьи — познакомить поближе юзеров с bash, рассказать про синтаксис, основные приемы и фишки языка, для того чтобы даже обычный пользователь смог быстренько написать простой скрипт для выполнения ежедневной(-недельной, -месячной) рутинной работы или, скажем, «на коленке» наваять скриптик для бэкапа директории.

Введение


BASH — Bourne-Again SHell (что может переводится как «перерожденный шел», или «Снова шел Борна(создатель sh)»), самый популярный командный интерпретатор в юниксоподобных системах, в особенности в GNU/Linux. Ниже приведу ряд встроенных команд, которые мы будем использовать для создания своих скриптов.

break выход из цикла for, while или until
continue выполнение следующей итерации цикла for, while или until
echo вывод аргументов, разделенных пробелами, на стандартное устройство вывода
exit выход из оболочки
export отмечает аргументы как переменные для передачи в дочерние процессы в среде
hash запоминает полные имена путей команд, указанных в качестве аргументов, чтобы не искать их при следующем обращении
kill посылает сигнал завершения процессу
pwd выводит текущий рабочий каталог
read читает строку из ввода оболочки и использует ее для присвоения значений указанным переменным.\
return заставляет функцию оболочки выйти с указанным значением
shift перемещает позиционные параметры налево
test вычисляет условное выражение
times выводит имя пользователя и системное время, использованное оболочкой и ее потомками
trap указывает команды, которые должны выполняться при получении оболочкой сигнала
unset вызывает уничтожение переменных оболочки
wait ждет выхода из дочернего процесса и сообщает выходное состояние.

И конечно же кроме встроенных команд мы будем использовать целую кучу внешних, отдельных команд-программ, с которыми мы познакомимся уже в процессе

Что необходимо знать с самого начала


1. Любой bash-скрипт должен начинаться со строки:

#!/bin/bash
в этой строке после #! указывается путь к bash-интерпретатору, поэтому если он у вас установлен в другом месте(где, вы можете узнать набрав whereis bash) поменяйте её на ваш путь.
2. Коментарии начинаются с символа # (кроме первой строки).
3. В bash переменные не имеют типа(о них речь пойдет ниже)

Переменные и параметры скрипта


Приведу как пример небольшой пример, который мы разберем:

#!/bin/bash
#указываем где у нас хранится bash-интерпретатор
parametr1=$1 #присваиваем переменной parametr1 значение первого параметра скрипта
script_name=$0 #присваиваем переменной script_name значение имени скрипта
echo "Вы запустили скрипт с именем $script_name и параметром $parametr1" # команда echo выводит определенную строку, обращение к переменным осуществляется через $имя_переменной.
echo 'Вы запустили скрипт с именем $script_name и параметром $parametr1' # здесь мы видим другие кавычки, разница в том, что в одинарных кавычках не происходит подстановки переменных.
exit 0 #Выход с кодом 0 (удачное завершение работы скрипта)


Результат выполнения скрипта:

ite@ite-desktop:~$ ./test.sh qwerty
Вы запустили скрипт с именем ./test.sh и параметром qwerty
Вы запустили скрипт с именем $script_name и параметром $parametr1


После того как мы познакомились как использовать переменные и передавать скрипту параметры, время познакомиться с зарезервированными переменными:

$DIRSTACK - содержимое вершины стека каталогов
$EDITOR - текстовый редактор по умолчанию
$EUID - Эффективный UID. Если вы использовали программу su для выполнения команд от другого пользователя, то эта переменная содержит UID этого пользователя, в то время как...
$UID - ...содержит реальный идентификатор, который устанавливается только при логине.
$FUNCNAME - имя текущей функции в скрипте.
$GROUPS - массив групп к которым принадлежит текущий пользователь
$HOME - домашний каталог пользователя
$HOSTNAME - ваш hostname
$HOSTTYPE - архитектура машины.
$LC_CTYPE - внутренняя переменная, котороя определяет кодировку символов
$OLDPWD - прежний рабочий каталог
$OSTYPE - тип ОС
$PATH - путь поиска программ
$PPID - идентификатор родительского процесса
$SECONDS - время работы скрипта(в сек.)
$# - общее количество параметров переданных скрипту
$* - все аргументы переданыне скрипту(выводятся в строку)
$@ - тоже самое, что и предыдущий, но параметры выводятся в столбик
$! - PID последнего запущенного в фоне процесса
$$ - PID самого скрипта

Условия


Условные операторы, думаю, знакомы практически каждому, кто хоть раз пытался на чем-то писать программы. В bash условия пишутся след. образом (как обычно на примере):
#!/bin/bash
source=$1 #в переменную source засовываем первый параметр скрипта
dest=$2 #в переменную dest засовываем второй параметр скрипта

if [[ "$source" -eq "$dest" ]] # в ковычках указываем имена переменных для сравнения. -eq - логическое сравнение обозначающие "равны"
then # если они действительно равны, то
echo "Применик $dest и источник $source один и тот же файл!" #выводим сообщение об ошибке, т.к. $source и $dest у нас равны
exit 1 # выходим с ошибкой (1 - код ошибки)
else # если же они не равны
cp $source $dest # то выполняем команду cp: копируем источник в приемник
echo "Удачное копирование!"
fi #обозначаем окончание условия.

Результат выполнения скрипта:
ite@ite-desktop:~$ ./primer2.sh 1 1
Применик 1 и источник 1 один и тот же файл!
ite@ite-desktop:~$ ./primer2.sh 1 2
Удачное копирование!

Структура if-then-else используется следующим образом:
if <команда или набор команд возвращающих код возврата(0 или 1)>
then
<если выражение после if истино, то выполняется этот блок>
else
<если выражение после if ложно, тот этот>
В качестве команд возвращающих код возврата могут выступать структуры [[ , [ , test, (( )) или любая другая(или несколько) linux-команда.
test - используется для логического сравнения. после выражения, неоьбходима закрывающая скобка "]"
[ - синоним команды test
[[ - расширенная версия "[" (начиная с версии 2.02)(как в примере), внутри которой могут быть использованы || (или), & (и). Долна иметь закрывающуб скобку "]]"
(( )) - математическое сравнение.
для построения многоярусных условий вида:
if ...
then ....
else
if ....
then....
else ....

для краткости и читаемости кода, можно использовать структуру:
if ..
then ...
elif ...
then ...
elif ...

Условия. Множественный выбор


Если необходимо сравнивать какоую-то одну переменную с большим количеством параметров, то целесообразней использовать оператор case.
#!/bin/bash
echo "Выберите редатор для запуска:"
echo "1 Запуск программы nano"
echo "2 Запуск программы vi"
echo "3 Запуск программы emacs"
echo "4 Выход"
read doing #здесь мы читаем в переменную $doing со стандартного ввода

case $doing in
1)
/usr/bin/nano # если $doing содержит 1, то запустить nano
;;
2)
/usr/bin/vi # если $doing содержит 2, то запустить vi
;;
3)
/usr/bin/emacs # если $doing содержит 3, то запустить emacs
;;
4)
exit 0
;;
*) #если введено с клавиатуры то, что в case не описывается, выполнять следующее:
echo "Введено неправильное действие"

esac #окончание оператора case.

Результат работы:
ite@ite-desktop:~$ ./menu2.sh
Выберите редатор для запуска:
1 Запуск программы nano
2 Запуск программы vi
3 Запуск программы emacs
4 Выход

После выбор цифры и нажатия Enter запуститься тот редактор, который вы выбрали(если конечно все пути указаны правильно, и у вас установлены эти редакторы :) )
Прведу список логических операторв, которые используются для конструкции if-then-else-fi:
-z # строка пуста
-n # строка не пуста
=, (==) # строки равны
!= # строки неравны
-eq # равно
-ne # неравно
-lt,(< ) # меньше
-le,(<=) # меньше или равно
-gt,(>) #больше
-ge,(>=) #больше или равно
! #отрицание логического выражения
-a,(&&) #логическое «И»
-o,(||) # логическое «ИЛИ»

С основами языка и условиями мы разобрались, чтобы не перегружать статью, разобью её на несколько частей(допустим на 3). Во второй части разберем операторы цикла и выполнение математических операций.

UPD: Исправил некоторые ошибки
UPD: Обновил часть про условия if-then-else

Статьи на unix-admin.su
Михаил @ite
карма
52,0
рейтинг 0,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Администрирование

Комментарии (114)

  • +6
    Читайте Advanced Bash-scripting guide и Linux phrasebook Скотта Граннемана :)
    • +1
      Advanced Bash-scripting guide — действительно отличная книга :), а Linux phrasebook как-то хотел купить себе, но полистал и подумал, что быстрее будет пользовать --help и man )
    • +2
      Advanced Bash Scripting Guide на русском, 2004-ый год
      • 0
        Это я так, по поводу упоминания сего руководства. Вдруг кому пригодится.
  • +1
    А вы проверять свои примеры пробовали? Первый пример выдаст вовсе не то, что вы там понаписали, а вот это:
    $ ./test.sh qwerty
    /bin/bash: #указываем где у нас хранится bash-интерпретатор: No such file or directory
    А если первую строку исправить, то вот это:
    $ ./test.sh qwerty
    Вы запустили скрипт с именем ./test.sh и параметром qwerty\n
    Вы запустили скрипт с именем $script_name и параметром $parametr1

    • 0
      В пером примере ошибка появляется потому, что строчка с коментарием переходит на следующую строку. Коментарии я уже пишу после того как оттестю программу
      А в «qwerty\n» — мой косяк ) \n должен быть за скобкой ", приношу извинения
      • 0
        1. Комментарии никуда не переходят. Просто Shebang их не поддерживает.
        2. \n там вообще не нужен.
        • 0
          поправил, спасибо
  • 0
    в любом случае спасибо, полезная заметка.
  • 0
    2)
    /usr/bin/vi # если $doing содержит 2, то запустить nano
    ;;
    3)
    /usr/bin/emacs # если $doing содержит 3, то запустить nano


    в комментах ошибка.
  • 0
    Спасибо. Давно хотел познакомиться с синтаксисом BASH'a. :)
    Буду читать вашу серию постов об этом языке.
  • +1
    2 года использую баш в повседневных задачах, но с трудом понял то, что уже знаю, как это будут понимать новички — не понимаю.
    • +2
      Я уже сейчас конец предложения понять не могу :(
    • 0
      А что конкретно не понятно? Примеры? Описания? Я был бы рад критике, но поконкретней пожалста и попонятней))
      • 0
        Может я немного не понял ваши намерения, но создается такое впечатление, как будто вы хотите рассмотреть баш как язык программирования, в отрыве от реалий и основных задач, для которых он используется. Сразу начали с передачи параметров скриптам, выместили кучу редко используемых операторов, рассмотрели все возможные операторы условий для циклов… Если ваша цель — по быстрому рассказать кодеру об еще одном языке программирования, то подход в принципе верен. Если же вы хотели познакомить с удобным инструментом решения повседневных задач новичка в мире *nix, то вы его только отпугнете.
        Если вы хотели добиться второго, то лучше начать с примеров вроде cat some.log | grep error или echo >> ass=true ~/.mplayer/mplayer.conf
        • 0
          Свою цель я описал в первом абзаце.
          • 0
            неужели вы с этого учились писать скрипты на коленке? :)
  • 0
    O'Relly Bash Cookbook — шикарная штука для начинающего. А то пока с експаншэнами всеми разберешься, писать расхочется уже: порог освоения высокий очень. А так, в одной руке www.gnu.org/software/bash/manual/bashref.html, а в другой кукбук.

    Эх. Вырасту, вот, для GUI аналог bash сочиню. Не система диктует что делать, а наоборот. Процедурные… проэктивные рабочие среды… ч-т… Организация рабочего пространства.
    • 0
      tcl/tk же.
      tcl — командный язык типа bash, но гораздо более расширенный. tk — простейшая библиотека для написания gui.
      • 0
        надо посмотреть.
        Вообще, я имею ввиду, эту фишку баша, что в гамках командного интерфейса ты посредством пайпов и тп и многочисленных утилит можешь себе дворцы в терминале строить. То есть, для GUI аналогом были бы механизмы перенаправления потоков даных, соответствующие интерфейсы для утилит и инструменты для сборки комплексов подстать особенностям GUI как такового.
        То есть, виджет, выдающий сколько в гугл-ридере новостей про bash я сейчс за месяц =) можт и могу наваять, а адекватных GUI средств для подобного рода выкрутасов пока нет. Даже концепций.

        Это я все к тому, что современный юниксовый GUI, решив идти со всеми, потихонюку перенимает неповоротливость и отсутствие хоть сколько нибудь адекватной гибкости, присущие другим известным операционным системам.
        • 0
          Услышав про гамак, сразу как-то вспомнилась фраза про секс в гамаке, но это так к слову. А про gui, я думаю к нему не надо примешевать логику. Лучше, как в паттерне mvc, Gui — будет view и controller, то есть в его задаче будет только связь с консольными приложениями или ядром программы.
          П.С. На тикле в принципе за пару часов могу такую прогу написать, у гугл ридера же апи нормальный, правда скорее всего придется скачивать всю ленту и здесь сортировать, но я апи только бегло посмотрел)
  • 0
    На самом деле оператор условия имеет вид:
    if command
    then
    list
    elif
    list
    else
    list
    end if

    [[ — это специальная команда, которая возвращает результат указанного внутри выражения

    то есть условие «if grep -q root /etc/passwd» тоже нормально сработает
    • 0
      а еще [ = test :)
      • 0
        Не совсем. Квадратная скобочка требует парной закрывающей, test — не требует…
        • 0
          Но, так или иначе, [ — это симлинк на test. Просто при вызове [ эта команда требует обязательный аргумент ] :)
          Однако, это уже всё тонкости. Просто некоторые считают [ ] конструкцией оболочки, в то время как это обычный запускаемый бинарник.
          • 0
            ubique@ubique ~ $ ls -alho /usr/bin/[
            -rwxr-xr-x 1 root 38K Jun 17 2008 /usr/bin/[
            ubique@ubique ~ $ ls -ahlo /usr/bin/test
            -rwxr-xr-x 1 root 26K Jun 17 2008 /usr/bin/test
            ubique@ubique ~ $ uname -o
            GNU/Linux
            • 0
              Правда ваша :) Перед тем как написать не проверил на других системах. В альте у меня симлинк стоит, в редхате два разных бинарника, а в слаке вообще и [, и test, лежащие в /usr/bin являются симлинками на соответствующие бинарники в /bin
          • +2
            Но, так или иначе, [ — это симлинк на test
            А если вы используете busybox, то у вас вообще все утилиты будут symlink'ом на один файл. Теперь будете говорить что ls, cp и rm — это одно и то же?
            Просто некоторые считают [ ] конструкцией оболочки, в то время как это обычный запускаемый бинарник.
            Нет, это не «обычный запускаемый бинарник». Сравните:
            $ touch test.txt
            $ if [ -N "test.txt" ]; then echo "test.txt is modified"; else echo "test.txt is not modified"; fi
            test.txt is modified
            $ if /usr/bin/[ -N "test.txt" ]; then echo "test.txt is modified"; else echo "test.txt is not modified"; fi
            /usr/bin/[: extra argument `-N'
            test.txt is not modified
            Поведение встроенное команды и внешней отличается. Более того: внешняя команда живёт в /usr/bin и, соответственно, не может быть использована в rc-скриптах! В более старых shell'ах это был «обычный запускаемый бинарник», в bash — это конструкция оболочки. Совместимая на 99%, но, как вы говорите, «это всё уже тонкости»…
            • 0
              Повержен в пух и прах, признаю все свои ошибки. :)
              Оказывается, всё давно изменилось…
  • 0
    я бы еще про chmod упомянул :) без
    chmod +x script.sh
    ./script.sh работать не будет :) для некоторых это неочевидно
    • 0
      В первой версии статьи это было, но ввиду неожиданного отключения электричества и разобранного УПСа на столе, она не сохранилась(
  • –1
    Простите за небольшой оффтопик, но есть такой замечательный шелл как fish — он чем то похож на питон и гораздо более юзерфрендли чем баш. Ну по крайней мере мне так показалось.
    Новичкам его советую однозначно, остальным — по желанию =)
    • 0
      Существует множество разных шеллов различной степени дружелюбности и гиковости, однако bash — это стандарт, его синтаксис должен понимать каждый. А вот остальные, как раз, по желанию.
      • 0
        Стандарт для написания скриптов — sh.
        • +1
          Не поленился и проверил на разных системах командой
          grep -sR ^#! /etc|perl -F: -ane 'chomp $F[1];$F[1]=~/^#! ?([^ ]+).*$/;$h{$1}++;END{while (($shell,$count)=each %h){print "$shell $count\n"}}'

          Fedora 9:
          /usr/bin/perl 1
          /bin/sh 703
          /usr/bin/pulseaudio 1
          /bin/csh 1
          /bin/bash 656

          Ubuntu 8.10:
          /usr/bin/perl 4
          /bin/sh 520
          /usr/bin/pulseaudio 1
          /usr/bin/python 2
          /bin/bash 27

          Debian
          /usr/bin/perl 1
          /bin/sh 166
          /usr/bin/install-menu 5
          /bin/bash 9

          Т.е. в некоторых случаях bash действительно используется как основное средство написания скриптов, но большая часть скриптов все-таки на sh.
          • 0
            Принято писать на sh, а не каких-то других скриптах, потому что sh предоставляет необходимый минимальный функционал. И то что будет нормально работать на sh, с очень большой вероятностью будет работать и на других интерпретаторах.
  • +2
    >1. Любой bash-скрипт должен начинаться со строки:
    #!/bin/bash

    Извините, но сие не есть правда. Шебанг нужно указывать только в случае, если текущий интерпретатор отличается от того, на языке которого написан скрипт. Т.е., если дефолтовым шеллом у вас csh — то без шебанга sh-скрипт не отработает; точно так же не отработает под любым шеллом perl-скрипт без указания #!/usr/bin/perl в начале его и запуске через ./script.pl
    • +1
      Лучше на это не полагаться. Мало ли какой shell использует человек…
    • 0
      автор наверное написал так, чтоб не пугать новичков =)
      • 0
        Да, действительно. Целью статьи, я поставил для себя описать минимум для работы и более-менее свободного(и удобного) написания скриптов. Кто захочет, тот сам найдет больше информации. Все равно в рамках 1ой ознакомительной статьи не описать всего.
    • +3
      А ещё можно писать, к примеру:
      #!/usr/bin/env perl
      Тоже будет работать =)
    • 0
      Однажды мой знакомый полдня убил, чтобы понять, почему в слаке не отрабатывает скрипт /etc/ppp/ip-up после поднятия pptp-подключения. При том, что если запускать скрыптик вручную, то команды предательски выполняются.
      Оказалось, что он забыл поставить волшебный шебанг в начало файлика, и pppd не смог его запустить.

      Всего один пример, но, блин их ведь куча может быть :)
    • 0
      Кстати, а /bin/sh не умеет что-то из того, что есть в статье?
  • –1
    О, то что надо, спасибо, я как раз сейчас «грызу» консоль =)
  • 0
    Хотелось бы чтобы вы не обошли стороной именно бэкапы. :)
    Грубо говоря — есть сервер с Н пользователей — у каждого свои проекты. Вот хотелось одним скриптом собирать все подпапки с проектами и каждый класть в отдельный архив.
    Т.е. нужно знать — как обходить директории и как выполнять программы. тар, например. :)
    • 0
      Если хотите ознокомиться с стандартными рецептами бекапов в nix — попробуйте почитать книгу «Unix backup and recovery»
    • 0
      Немного кривой код, но рабочий.
      find * -maxdepth 1 -type d | xargs -I '{}' tar cvf '{}.tar' '{}'
      Выбирает все подпапки из папки и каждую кладет в отдельный tar файл. Для настройки даты последнего изменения итп смотрите man find.
      • +1
        find. -maxdepth 1-mindepth 1 -type d -exec tar czf '{}.tgz' '{}' \;

        find.unixpin.com
        • 0
          Большое спасибо вам. Всегда думал, что существует простой путь юзания имени файла в find -exec несколько раз.
  • 0
    Не обязательно любой shell скрипт должен начинать с #!(sha-bang). Например — подключение shell скриптов с помощью. — тот скрипт который мы подключаем не обязан иметь sha-bang в начале.
    Почему пост исключительно направлен на тех, кто использует linux? bash практически де-факто стандарт для всех пользовательских shell'ов. Где-то встречал рекомендацию, чтобы оформлять sha-bang так # !/bin/sh. Именно пробел после #. Только не понял для чего это используется:)
    Если планируется писать скрипты, которые должны работать на всех видах nix, то лучше писать исключительно на sh, не употребляя дополнительные возможности bash или какого-нибудь специфичного интепретатора.
    • 0
      Пробел после # может использоваться чтобы обмануть шибко умный парсер на каком-нибудь сайте. А в реальном файле его быть не должно. Ибо в fs/binfmt_script.c:
      25         if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang))
      26                 return -ENOEXEC;
      Куда там пробел вставлять?

      P.S. bprm->sh_bang — это хитрый хак для как-бы-вставления в начало IA32-файла строки #!/usr/bin/em86, больше он нигде не используется…
    • +1
      Пробел после восклицательного знака, а не после октокорпа. Вставлять этот пробел рекомендует «Autoconf Manual: 10. Portable Shell Programming» [1]. Однако «The '#!'-magic, details about the shebang mechanism on various Unix flavours» [2] опровергает необходимость этого. Также неверно утверждение khim («в реальном файле его быть не должно»), это видно даже по приведённому отрывку кода.

      [1] www.gnu.org/software/autoconf/manual/autoconf-2.57/html_chapter/autoconf_10.html#SEC114
      [2] www.in-ulm.de/~mascheck/various/shebang/#details

      P.S. Вставить нормальные линки не позволила низкая карма :(
      • 0
        Спасибо большое!
      • –1
        Давайте не приписывать мне слов, которых я не говорил. После #! пробел может быть нужен на старых системах, внутри #! — никогда.
        • 0
          Прошу прощения. Вы действительно правы по поводу того, что внутри «#!» пробела быть не должно. Позволю, однако, не согласиться с тем, что «после #! пробел может быть нужен на старых системах». Приведите пример хотя бы одной системы, требующей 32-битный magic «#! /», а не 16-битный «#!».
  • +1
    «это еще и превосходный скриптовый язык программирования.»
    Да ладно вам, язык очень и очень хреновый, если можно него не юзать — нужно его не юзать. Единственный плюс (да, если это всё же sh) — кроссплатформенность.

    С другой стороны уметь читать и писать на нём (хотя бы со словарём, а лучше — без) пока ещё крайне желательно, в силу как естественных причин, так и инерциальности мышления.
    • 0
      А аргументировать сможете?
      • +1
        Какую из двух реплик?

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

        Если вторую — да, куча всего уже написано на sh/bash, уметь разбираться в этом и дорабатывать тоже нужно. Но если есть возможность переписать на чём-то более читабельном — почему нет?
  • +1
    Вот так и знал, что Вы стороник python. Вы предлагаете ставить на каждый сервер python?
    Синтаксис наооборот — наиболее простой, конечно если не стараться все запутать, впрочем это можно сделать на любом языке. Любые Вещи делаются приятнее? А сделайте мне, вот такой простой аналог на python `cat /etc/passwd | awk -F ':' '$1>1000{$print $3}' | sort -r`. Говорите приятнее? Про использование повторно — вообще не понял. Что Вы shell скрипты повторно использовать не можете? А короткие команды можно и в alias загнать. Если Вы имели ввиду использование библиотек, то кто Вам мешает подключать другие shell сценарии в свой? Только что не знание того, что это можно делать.

    Shell — стандарт серверных скриптов и слава богу, python'y до этого еще далеко. Единственное причина, из-за которой можно уходить от shell — необходимость реализации более сложной логики в скриптах. Но никто не говорит, писать различные engine или биллинг на sh.
    • –2
      В вашем примере используется awk, с каких пор awk является частью sh? Да и молчу я вообще про него.
      Я не сторонник Python, я сторонник понятного, читаемого кода, да и подцепить любую shell команду к нему не сложно.

      «Синтаксис наооборот — наиболее простой» Короткий ≠ простой.
      Почему, чёрт побери, условие в квадратных скобочках, где нормальные выражения?
      Кто придумал ;; в case?
      Почему всё так стремится быть брейнфаком?
      Почему просто не взяли синтаксис Си, доработали его до того уровноя, на котором легко можно обрабатывать массивы в циклах (for (xxx in yyy) {})?

      «Вы предлагаете ставить на каждый сервер python?» Слова-обобщения мне всегда не нравились. Всему своё место.
      • +1
        Потому что sh без сторонних программ — не дает толком ничего. shell является прослойкой между терминалом пользователя и сторонними програмами, которые являются частью base-системы и которые представляют всю мощь программирования на shell. И их функционал достаточен практически для любого ряда задач. Повторяю еще раз, читаемость кода ни столько заслуга самого языка, а сколько того, кто на нем пишет. На любом языке(кроме гик-язкыков) можно писать как понятно, так и нет. Надеюсь примеров приводить Вам не нужно.

        Про синтаксис и квадратные скобочки — не смешите, если Вы настолько приверженец c-based синтаксиса, то от python Вас просто должно воротить.

        (for (xxx in yyy) {}) — пишется два цикла и все.

        Повторяюсь, тот круг задач, который обычно решают shell сценарии решается ими хорошо и прикручивание сбоку избыточного функционала, что порождает за собой существование лишних сущностей — в корне не правильно.
        • 0
          Вот именно, без сторонних программ — ничего.
          Читаемость безусловно сильно зависит от человека. Да и вообще вы в определённом смысле разумеется правы. А я вот свято верю, что написать, при необходимости, можно разно и на многом.

          Но личный опыт мне подсказывает, что мне бы было удобнее писать многие вещи всё же на Python, чем когда я их писал на sh.

          Предлагаю спор закончить на этом, я вашу точку зрения понял, и даже готов признать что выражение «Любые вещи, делаются на том же Python гораздо приятнее» неуместно.
      • 0
        >В вашем примере используется awk, с каких пор awk является частью sh?
        а так же ls, cat, grep, cut, cd, ln, chmod, echo, time, false, dd… это же все на С написано и давно скомпилировано!!! срочно убрать из всех скриптов!!!1стоадинацать
      • 0
        Кстати замечание ваше на тему того, что awk — не часть shell'а не вполне уместно. Вот версия того, что ubique, как я полагаю, хотел написано (а написал он нечто неработающее во-первых и не имеющее смысла во-вторых):
        $ while IFS=':' read I J K r; do if ((K>1000)); then echo "$I"; fi; done < /etc/passwd | sort -r
        sort — это часть coreutils без которых bash использовать заруднительно. Работает? Да. Коротко? Несомнено. Сам чёрт ногу в этом сломает? Разумеется.
        • 0
          про awk, это я к тому сказал, что в Убунту (не знаю как там в настоящих дебианах) awk не входит в комплект того, что ставится в систему по умолчанию. Тут даже пакета 2 разных mawk и gawk.
        • 0
          cat /etc/passwd | awk -F ':' ' $3 >1000 {print $1}' | sort -r

          Вот что я имел ввиду, просто было поздно.

          В моем выражении черт ногу не сломит, а в Вашем — да. Полагаю Вы согласитесь с тем, что «черт ногу сломит» зависит только от того, кто пишет. И не более.
          • 0
            В моем выражении черт ногу не сломит, а в Вашем — да.
            В вашем понять что-либо ничуть не легче, поверьте. Особенно человеку не очень хорошо знающему awk. Тот факт что я с первой попытки написал работающую версию, а вы со второй — тоже говорит о многом.

            • 0
              Перестаньте цепляться к опискам. Это не делает Вам чести.
          • 0
            Полагаю Вы согласитесь с тем, что «черт ногу сломит» зависит только от того, кто пишет.
            Не только. Важно ещё кто читает. Для меня версия с ипользованием bash'а без awk читается проще, к тому же она расширяется легче.
        • 0
          А если Вы не уловили смысла — то это список пользовательских аккаунтов, не системных :)
          • –1
            Неправда. У меня, например, nobody имеет номер 65534 — но да, я примерно так и понял: мой скрипт и ваш второй выдают список пользователей зарегистрированных через /etc/passwd (а это, понятно, не все пользователи) с UID больше 1000 (то есть одного нормального пользователя они таки теряют). И то что в вашем втором скрипте содежится пара ошибок как раз и указывает на то, что подобные трюки больше годятся на то, чтобы поражать неискушённых, чем на то, чтобы ими реально можно было пользоваться. Процедура написанная и отлаженная на python'е будет писаться дольше, но есть шанс что она будет правильной. А подобный «грязный хак» легко написать прямо в командной строке, получить неверный результат и потом долго пытаться понять — в чём, собственно, беда…
            • 0
              >зарегистрированных через /etc/passwd (а это, понятно, не все пользователи)
              приведите пример

              Стандартный пул пользовательских uid'ов начинается с 1000.
              Это не грязный хак, это реальное использование unix систем, и если Вы не умеете использовать базовые утилиты и каждый раз городите свой велосипед на языка программирования — Вы не понимаете UNIX.
              • 0
                >зарегистрированных через /etc/passwd (а это, понятно, не все пользователи)
                приведите пример
                Ну вот, например, с машины на которой я сейчас сижу:
                $ cat /etc/passwd | awk -F ':' ' $3 >1000 {print $1}' | sort -r
                nobody
                $ id -u
                13197
                Причём всё же очевидно (мне даже в голову не пришло что про подобный вариант «развития событий» нужно говорить явно):
                $ cat /etc/pam.d/common-auth
                auth sufficient pam_unix.so
                auth sufficient pam_krb5.so retain_after_close forwardable refresh_creds use_first_pass
                auth required pam_deny.so
                И после этого вы ещё рассуждаете о больших системах? Смешно.
                Стандартный пул пользовательских uid'ов начинается с 1000.
                Обычно, но не всегда.
                Это не грязный хак, это реальное использование unix систем, и если Вы не умеете использовать базовые утилиты и каждый раз городите свой велосипед на языка программирования — Вы не понимаете UNIX.
                Как видим на моём примере — это таки грязный хак. Список пользователей вообще не должен жить (и не живёт) в /etc/passwd, а для управления пользователями есть специальные утилиты.
                • 0
                  Кроме пользователя nobody еще какие-то есть?
                  Я просил привести аналог для поиска в /etc/passwd, никакие другие механизмы атворизации(like kerberos) я не затрагивал. Примера Вашего я не увидел. Привести его сможете?
    • +1
      Shell — стандарт серверных скриптов и слава богу — к сожалению, python'y до этого еще далеко.

      То, что вы привели — это то, что я могу набрать в командной строке для однократного пользования. Если же это приходится делать часто, то я предпочту скрипт на 10 строк на Python'е или даже, прости господи, на Perl'е. Просто потому что их будет приятнее читать.

      А ставить на каждый сервер Python — почему бы и нет? Он не так много места занимет. Ибо как вы сами заметили bash без кучи дополнительных примочек вообще нифига не умеет, а Python во многом самодостаточен. Нужны только совсем системно-зависимые команды (типа modprobe).

      Если же вам не нужно программировать (ну совсем простая система — роутер какой-нибудь), то к вашим услугам nash. А bash жив только за счёт того, что от вредных привычек сложно избавляться. И мне в том числе. Но пропогандировать его…
      • 0
        Согласен с вами, сам использую для этого javascript, со всей его мощью и интерпретатором jsdb.
        Куму интересно, то вот линк на него
      • 0
        Да какие примочки? Любой shell сценарий использует base утилиты из системы. И для тех задач, которые решаются shell-сценариями их хватает с избытком.
        • +1
          Любой shell сценарий использует base утилиты из системы.
          1. awk далеко не во всех системах входит в base system, так что вы сами себе противоречите своим примером.
          2. Cравните суммарный вес этих утилит плюс bash'а и python'а. Разница будет невелика и ещё не факт что проиграет python.
          3. В том-то и дело что их «хватает с избытком» — нужно держать в голове кучу бессмысленных сведений чтобы читать чужие скрипты, но для нормального программирования bash всё равно не годится.

          Мне кажется правильное воприятие всего этого: bash — неизбежное зло.
          • –2
            Во всех production системах awk входит в base-system.
            Python — слишком сырой и использовать его для простых серверных скриптов может только фанатик.
            Если Вы не знаете базовых утилит unix — Вам лучше с ним распрощаться навсегда. Вам было бы полезно ознакмоиться с идеологией UNIX. Могу посоветовать книгу Эрика Рэймонда — «Искусство программирования в UNIX».
            • 0
              Во всех production системах awk входит в base-system.
              О как. Вот прямо даже так. То есть все системы где нет awk автоматически объявляются не-production?
              Python — слишком сырой и использовать его для простых серверных скриптов может только фанатик.
              И в чём же заключается его сырость?
              Если Вы не знаете базовых утилит unix — Вам лучше с ним распрощаться навсегда. Вам было бы полезно ознакмоиться с идеологией UNIX. Могу посоветовать книгу Эрика Рэймонда — «Искусство программирования в UNIX»
              А с чего вы решили что я ней не знаком? И что эту книгу я не читал? Или любой человек, прочитавший её и не воспылавший нежной любовью к awk автоматически записывается в душевнобольные?
              • –1
                Нет. На сервера принято ставитьтолько production системы, и всякие экзотические дистрибутивы к ним не относятся. А во всех боевых дистрибутивах awk есть.
                Сырость заключается хотя бы в полной несовеместимости 2 и 3 ветки. Это достаточное условие.
                С того, что Вы не понимаете или не хотите призновать того, что в ней говориться.
                • 0
                  Нет. На сервера принято ставитьтолько production системы, и всякие экзотические дистрибутивы к ним не относятся. А во всех боевых дистрибутивах awk есть.
                  Кем принято? Когда принято? Почему принято? Что такое «боевой» дистрибутив?
                  Сырость заключается хотя бы в полной несовеместимости 2 и 3 ветки. Это достаточное условие.
                  О как. То есть любая система, которая развивается (ну например bash, совместимость первой и второй версий оставляет желать лучшего) для production систем не годится. Хм… А что там вообще может быть установлено.
                  С того, что Вы не понимаете или не хотите призновать того, что в ней говориться.
                  То есть любой человек, не согласный с выводами вашей «суперкниги» автоматически ничего не понимает в unix? Бред.
                  • 0
                    production системы(nix) — freebsd, и несколько дистрибутивов linux. Которые суммарно покрывают 98% серверных установок nix систем. Принятно ставить системными администраторами, которые имееют порядочный опыт работы.

                    Bash был всегда sh compatible. Во всяком случае bash скрипты спокойно читались. О полном различии не может быть и речи.

                    Использование развивающихся, сырых, не достаточно проверенных систем обычно не принятно на production системах. Вы можете использовать их у себя на тестовых машинах, но не в продакшн. За примерами далеко ходить не стоит. Гонка за всем новым и современным зачастую ничего не приносит кроме энергии, потраченной на установку этого нового и решения проблем, принесеннымм этим новым. Повторяюсь, речь идет о production системах. У себя дома — можете городить что хотите.

                    Вы книгу читали? Можете привести пункты, с которыми не согласны? И желательно аргументировать.
                    • 0
                      production системы(nix) — freebsd, и несколько дистрибутивов linux. Которые суммарно покрывают 98% серверных установок nix систем. Принятно ставить системными администраторами, которые имееют порядочный опыт работы.
                      Если мы говорим о типичных средних конторах — то, пожалуй, соглашусь. Но на них свет клином не сошёлся и понятие «production system» они таки не покрывают. Является ли система, выпускаемая десятками миллионов экземпляров (как какой-нибудь WiFi-роутер) production системой? Явлется ли BluGene/L production-системой? По-моему вы слишком сужаете рамки того, что вы называете «production системой».
                      Bash был всегда sh compatible. Во всяком случае bash скрипты спокойно читались. О полном различии не может быть и речи.
                      Наоборот: о 100% совместимости никогда не шло и речи. Например такая вещь как var2=$"$var1" превратилась в bash2 в var2=${!var1} — но при этом старый синтаксис перестал работать!
                      Использование развивающихся, сырых, не достаточно проверенных систем обычно не принятно на production системах.
                      Если это принять за аксиому, то стоит принять также и факт, что python — не является таковой. Среди тех «нескольких дистрибутивов linux», о которых вы говорили выше есть и такой зверь как RHEL (RedHat Enterprise Linux — или вы скажете что и им никто не пользуется?). Там большая часть утилит администрирования написана на Python'е.
                      Вы можете использовать их у себя на тестовых машинах, но не в продакшн. За примерами далеко ходить не стоит. Гонка за всем новым и современным зачастую ничего не приносит кроме энергии, потраченной на установку этого нового и решения проблем, принесеннымм этим новым. Повторяюсь, речь идет о production системах. У себя дома — можете городить что хотите.
                      Ух ты, сколько пафоса. Слова-то верные, но причём тут Python?
                      Вы книгу читали? Можете привести пункты, с которыми не согласны? И желательно аргументировать.
                      Например его утверждения про полезность текстовые конфиги и хранения данных в текстовых форматах — весьма спорно. Активное использование текстовых конфигов обозначает что вы будете иметь миллион парсеров, которые будут пытаться парсить одни и те же конфиги и наверняка по разному! Использование чего-нибудь вроде Protocol Buffers или Apache Thrift ничуть бы не усложнило работу с конфигами (если забыть про bash), но дало бы возможность обойтись меньгим количеством «велосипедов». К сожалению историю нельзя повернуть вспять…
                      • 0
                        Вы посмотрите на название поста, посмотрите на чем и для чего предполагается писать скрипты и поймете, что ни о чем другом речь и не шла.

                        RH под рукой нет, но вот
                        Fedora 9:
                        /usr/bin/perl 1
                        /bin/sh 703
                        /usr/bin/pulseaudio 1
                        /bin/csh 1
                        /bin/bash 656
                        Что-то я не вижу здесь python. Если Вы говорите про средства администрирования, like pw, useradd, passwd, etc — удивлю Вас, они обычно на c пишутся.

                        Если парсеры будут писать идиоты, то да — конфиги будут парситсья по разному. И лучше все таки тектовые конфиги. Оставьте Ваши мечты и посмотрите на самые популярные open source проекты. Какими конфиг. файлами они пользуются?

                        Пожалуйста, давайте прекратим нашу беседу. Правда, мне надоело тратить свое время в пустую.
        • 0
          Любой shell сценарий использует base утилиты из системы.
          1. awk далеко не во всех системах входит в base system, так что вы сами себе противоречите своим примером.
          2. Cравните суммарный вес этих утилит плюс bash'а и python'а. Разница будет невелика и ещё не факт что проиграет python.
          • 0
            Только не забывайте о том, что эти утилиты всегда есть в системе, а python нужно ставить дополнительно.
            • 0
              А это уже зависит кто и для чего делал систему…
              • –1
                Мне кажется Вы просто не имеете опыта работа с большим количеством серверов и не знаете реалий. Вашу точку зрения я понял, и пытаться Вас переубедить — бесполезно, тем более что позиция Ваша достаточно откровенно выглядит глупой. Спасибо за Ваши ответы.
                • 0
                  Мне кажется Вы просто не имеете опыта работа с большим количеством серверов и не знаете реалий.
                  Ну… смотря что считать «большим количеством серверов». В системах, с которыми работал я обычно было 100-200 серверов (в последнее время я сталкиваюсь с системами в 5'000-10'000 серверов, но вынужден признать что awk там есть… хотя python используется чаще) и они часто использовали специально под них заточенные дистрибутивы (да почти всегда — не годятся распространённые дистрибутивы под такие задачи без «обработки напильником»).
                  Вашу точку зрения я понял, и пытаться Вас переубедить — бесполезно, тем более что позиция Ваша достаточно откровенно выглядит глупой.
                  Я всегда готов сменить точку зрения под давлением фактов, но вот как раз с ними-то у вас туго: я вижу кучу неверных утверждений, а не какие-то факты с которыми я был бы готов согласиться. Как-то: во всех production системах awk входит в base-system — неверно: я сам общался с системами где awk не было. Вполне production. Или:Сырость заключается хотя бы в полной несовеместимости 2 и 3 ветки. Это достаточное условие. Тоже бред: переход с Java 1.4 на Java 1.5 был довольно-таки болезненным и с совместимостью там были напряги. Что не мешает Java быть и оставаться одним из самых используемых на production системах языком. Ну и так далее.

                  • 0
                    Повторяюсь, я говорил лишь о том, что там где shell может решать задачу нужно использовать его, а не python. Я не говорю о том, чтобы писать биллинг на sh.
                    И если Вас не затруднит, расскажите пожалуйста, с какими система в 5000-10000 серверов Вы работаете.
                    Примеры моих неверных утверждений в студию. За исключением не верного варианта первого скрипта(о котором Вы не смогли устоять и сообщила аж целых два раза) и моего утверждения про пробел, не имеющего фактической смысловой нагрузки.

                    Хотя бы потому, shell скрипты быстрее python аналогов. Примеры сможете привести, для чего использовался python на этих серверах?
                    Примеры production систем, где нет awk привести можете?
                    Про java — говорим о python, так говорим о python.
                    • –1
                      Хотя бы потому, shell скрипты быстрее python аналогов. Примеры сможете привести, для чего использовался python на этих серверах?
                      Shell скрипты, как правило, медленнее python аналогов. А уж при использовании RPC (а как вы ещё собираетесь управлять кластером в несколько тысяч компьютеров?) из bash'а — это превращается в такой кошмар, что говорить о скорости их написания не приходится.
                      Примеры production систем, где нет awk привести можете?
                      Легко — любой WiFi router. Обычно там нет и python'а, но если вам нужен не один роутер, а система из нескольких сотен подобных зверей разбросанных по всему миру… в общем по-моему вы очень узко смотрите на понятие «production system».
                      • 0
                        Да как медленее? Пример — shell быстрее распарсит и посчитает статистику по какому-нибудь лог файлу. Вы так и не сказлаи для чего используется этот python на серверах. Назовите пожалуйста. Мы говорим о серверах — так о серверах, не изменяйте понятия.
  • +1
    обожаю bash отличная статься!!!

    ps вобще-то не обязательно указывать первой строкой путь к интерпретатору (это относится не только к башу). это необходимо, если интерпретатор не указывается явно при запуске
  • 0
    Статья полезная, буду читать, но опечатки нужно исправить, очень портят впечатление. Обычный спеллчекер найдет массу перепутанных и пропущенных букв.
  • +2
    Мощю юникса не столько в его командных оболочках, сколько в его утилитах, и конвеерах.
    Новичкам, на мой взгляд, гораздо полезнее и интересней узнать не о переменных баша, а о конструкциях с find, grep, и т.д.
  • –2
    Ого! Не одного комментария типа «а я думал статья про башорг о_О».
    • –2
      Ого! Ни одного комментария типа «ого, ни одного комментария типа \»а я думал статья про башорк\""…
      Чёрт, уже один есть.
  • 0
    На sh ещё сайты можно делать :)
    • 0
      И даже webserver напитьсать)
  • 0
    >> Таким образом оператогр условия имеют следующий вид:
    >> if [[ «что-то» <оператор логического сравнения «с чем-то»]]

    Это не совсем верно, вернее совсем не верно.
    [[ expression ]] — это встроенная команда bash, возвращающая 0 или 1 в зависимости от того что с условиями в скобках творится. Можно использовать и в отрыве от if:

    diesel@indie:/home$ [[ `pwd` =~ «diesel» ]] && echo OK || echo «Not OK»
    Not OK
    diesel@indie:/home$ cd
    diesel@indie:~$ [[ `pwd` =~ «diesel» ]] && echo OK || echo «Not OK»
    OK

    с другой стороны, if, как написано в man bash имеет формат:
    if list; then list; [ elif list; then list; ]… [ else list; ] fi
    где первый list исполняется и в зависимости от кода возврата будет выполнятся та или иная ветка условного оператора. То есть можно и вот так:

    diesel@indie:~$ if ls / > /dev/null 2> /dev/null ;then echo ok; else echo «not ok»; fi
    ok
    diesel@indie:~$ if ls /no-such-dir > /dev/null 2> /dev/null ;then echo ok; else echo «not ok»; fi
    not ok

    if [ expression ]; then или if [[ expression ]]; then — просто часто употребляются вместе, но if и [[ это две самостоятельные команды.
    • 0
      и чем мой код «совсем не верен»? Просто я считаю [[ ]] более универсальной структурой, и для понимания работы оператора if-then-else незачем захламлять текст(и мозги читателей) другими способами сравнения условий.
      • +2
        потому как if [[ ]] не является цельной структурой, — это две разных команды. это важно для понимания того что происходит.

        > if-then-else незачем захламлять текст(и мозги читателей) другими способами сравнения условий.

        в том то и дело что if не является командой для «сравнения условий». if является командой которая смотрит на код возврата команды, которую вы указываете собственно после if. и [[ ]] — просто самая популярная команда, которую часто подставляют — это не может быть более универсальной структурой по-определению, поскольку универсальность здесь как раз и состоит в том что за if может следовать любая другая команда.

        В следующих статьях Вы пообещали рассказать про циклы, с тем же while ситуация абсолютно такая же как и с if. и если Вы расскажите о конструкциях типа:
        ls | while read i; do do-smth-with-file "$i"; done
        то это как раз будет ненужное захламление мозга шаблонами: в if мы можем только сравнивать, а в while подставлять команды, или сравнивать (хотя на самом деле «сравнивать» — изначально просто еще одна команда)
        • 0
          Да, теперь я понял о чем вы, я недостаточно точно выразился. Коментарий верен только для примера приведенного в статье. Статью дополню
        • –1
          [ "$a" > "$b" ] && echo $a || echo $b
          • 0
            конструкция [ "$a" > "$b" ] всегда возвращает true
            подумайте над этим
            • +1
              (( "$a" > $b )) && echo $a || echo $b
      • 0
        ЗЫ: код верен, не верен комментарий.
    • 0
      Добавлю, что [[ — это т.н. башизм, тогда как test и [ — это встроенные в баш аналоги утилит из coreutils (в Linux). Т.о., использование [[ автоматически делает скрипт непортабельным.
      • 0
        Да, [[ лучше использовать только тогда, когда действительно оно надо, то есть делается что-то чего [/test не умеет(например, [[ вроде как умеет регулярные выражения ). Впрочем, башизм это — не плохо. Плохо это когда в bash-скрипте стоит #!/bin/sh, и зависимостей от bash нет.
      • 0
        т.е. вы хотите сказать, что если я использую [[, то такой скрипт не будет работать, скажем под *BSD? При условии что на linux и *bsd вресии bash одни.
        • 0
          Да будет конечно. Если там bash есть.
  • +1
    Многие не дооценивают удобство и простоту баша. Главное, не пытаться писать «монструозные» скрипты и всегда знать меру.

    Хочется сказать, что даже на баш скрипты можно и нужно писать тесты.

    Например, написать тесты можно очень просто с помощью bashtest утилиты.
    Тесты выглядят как примеры запуска. Примеры тестов можно найти в гитхабе проекта.

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