О разных командных оболочках Linux и Unix

    imageНаверняка почти все читатели Хабра знают оболочки sh и bash. Так же большинство из нас что-то слышали про zsh и tcsh. Однако на этом список существующих оболочек не заканчивается. Условно можно разделить их на три группы:

    • Клоны Bourne shell (bash, zsh)
    • C shell (csh, tcsh)
    • Базирующиеся на популярных языках программирования(psh, ipython, scsh)
    • Экзотические, специфические и все остальные

    О наиболее интересных из них и пойдет речь.

    Целью написания статьи не был обзор или классификация всех существующих командных оболочек. Просто хочу рассказать о некоторых интересных продуктах в этой области, расширить кругозор читателя. Буду рад. если этим сподвигну кого-то к более детальному изучению темы или даже к тому, чтоб перейти на другой шел.
    Сначала коротко о том, что же это такое. Командная оболочка или командный интерпретатор- это приложение предоставляющее пользователю интерфейс командной строки в которой тот либо вводит команды по отдельности, либо запускает скрипты состоящие из списка команд. Устно и в неофициальных текстах часто называется «шел», от английского shell — оболочка.

    Наибольшее распространение получили POSIX-совместимые оболочки, ведущие родословную от Bourne shell (шелл Борна), поэтому с него и начнем

    Bourne shell и его клоны


    Bourne shell, исполняемый файл: sh. Командная оболочка названная в честь своего создателя Стивена Борна. Большая часть операторов была заимствована им из языка Алгол 68. Вышла в 7-м издании операционной системы UNIX, где была оболочкой по умолчанию. До сих пор подавляющее большинство Unix-подобных систем имеют /bin/sh — символическую или жесткую ссылку на sh-совместимую оболочку.

    Bourne again shell, исполняемый файл: bash. Название можно перевести, как «Возрождённый шел Борна». Скорее всего самая популярная оболочка на сегодняшний день. Де-факто стандарт для Linux. Не буду на ней останавливаться, т.к. в интернете много хороших статей про bash. Например вот и вот.

    Z shell, исполняемый файл: zsh. Свободная современная sh-совместимая оболочка. Имеет ряд преимуществ перед bash касающихся в основном работы в интерактивном режиме. О ней на Хабре писали тут и тут
    Кроме того существует довольно много оболочек попадающих в эту группу: Korn shell (ksh) и Almquist shell (ash) etc но не будем подробно на них останавливаться.

    C shell


    C shell, исполняемый файл: csh Командная оболочка разработанная автором vi Биллом Джоем. За основу для скриптового языка csh был взят, как понятно из названия, язык C. Т.к. на тот момент, в 1978 г., это был наиболее популярный язык программирования среди разработчиков и пользователей BSD UNIX. В настоящий момент более популярна свободная реализация csh — tcsh.

    TENEX C Shell, исполняемый файл: tcsh. Именно в tcsh когда-то впервые появилось автодополнение. Является оболочкой по умолчанию в FreeBSD. Подробнее о ней почитать можно здесь.
    Для того чтоб наглядно показать разницу в синтаксисе приведу несколько примеров скриптов делающих одно и то же для csh и sh-совместимого командного интерпретатора.

    Условная конструкция:
    #!/bin/sh
    if [ $days -gt 365 ]
    then
       echo This is over a year.
    fi
    
    
    #!/bin/csh
    if ( $days > 365 ) then
       echo This is over a year.
    endif
    
    


    Множественное ветвление (Переключатель, Swich/case):
    #!/bin/sh
    for i in d*
    do
       case $i in
          d?) echo $i is short ;;
          *) echo $i is long ;;
       esac
    done
    
    #!/bin/csh
    foreach i ( d* )
       switch ( $i )
          case d?:
             echo $i is short
             breaksw
          default:
             echo $i is long
       endsw
    end
    


    Цикл вычисляющий 10 первых степеней двойки:
    #!/bin/sh
    i=2
    j=1
    while [ $j -le 10 ]; do
       echo '2 **' $j = $i
       i=`expr $i '*' 2`
       j=`expr $j + 1`
    done
    
    
    #!/bin/csh
    set i = 2
    set j = 1
    while ( $j <= 10 )
       echo '2 **' $j = $i
       @ i *= 2
       @ j++
    end
    
    


    Однако список фичь поддерживаемых свежими версиями bash, zsh и tcsh очень похож и выбор конкретной оболочки по большей части дело вкуса. С менее распространенными оболочками дело обстоит иначе. Тут различия существеннее.

    Командные оболочки, базирующиеся на популярных языках программирования.


    Perl Shell, исполняемый файл: psh. Оболочка сочетающая в себе функции вышеупомянутых оболочек и мощь языка Perl. Т.к. psh написана на perl она может запускаться даже на Windows. Несколько примеров использования psh:
     ls | s/y/k/                    # Замена c помощью регулярных выражений
     ls | { print ++$i, ": $_"; }q  # Быстрые фильтр. Внутри фигурных скобок выражение на perl, где $_ содержит одну строку вывода.
     netstat | { $_[1]>2; }g        # grep-фильтры. Выводятся только те строки для которых выражение в скобках возвращает true
     command >[=FOO]                # Перенаправление по дескриптору открытого файла 
     command >[2] file              # Эквивалентно command 2> file на bash. Перенаправляет в файл поток вывода и ошибок
     grep foo lib/**/*.pm           # Использование **, что означает текущий каталог и все подкаталоги 
    


    Scsh, исполняемый файл scsh. Командный интерпретатор с открытым кодом использующий в качестве скриптового языка Scheme 48. Не поддерживает стандартные для других оболочек функции (история команд, редактирование текста в командной строке, дополнение путей/команд). Рекомендуется написания скриптов, но не для интерактивной работы. Может прийтись по вкусу любителям функционального программирования. Ниже приведен пример скрипта, который выводит имена всех исполняемых файлов находящихся в каталогах из переменной окружения PATH
    #!/usr/local/bin/scsh -s
    !#
     
    (define (executables dir)
      (with-cwd dir
        (filter file-executable? (directory-files dir #t))))
    (define (writeln x) (display x) (newline))
     
    (for-each writeln
      (append-map executables ((infix-splitter ":") (getenv "PATH"))))
    


    IPython. Это интерактивная оболочка для языка программирования Python, имеющая ряд дополнительных функций. IPython имеет специальный профиль для работы в качестве системной командной оболочки. Способ запуска этого режима зависит, как я понял, от версии, но на моей машине это выглядит так:
    ipython3 --profile=pysh

    О IPython уже написано довольно много в том числе и на русском языке (ссылки в конце статьи). Постараюсь перечислить его основные фичи с точки зрения применения его как командной оболочки:
    • Кросплатформенность. Есть даже версия под Windows
    • Python версий 2.x или 3.x в качестве скриптового языка, расширенные возможности интроспекции
    • Автодополнение кода Python а так же имен файлов и системных команд.
    • История команд и макросы на ее основе
    • Механизм ускоряющий навигацию по каталогам, закладки и многое другое

    Как видите, по своим интерактивным возможностям IPython как минимум не уступает bash. Что же касается скриптов, то IPython будет удобен тем, кто знает python лучше чем bash. По сути скрипты на IPython будут отличаться от чистого питона только упрошенным вызовом системных команд. Приведу несколько примеров интеграции python и системных команд:
    # Допустим нам захотелось посчитать сумарный размер файлов логов dpkg:
    In [58]: cd /var/log/
    /var/log
    
    In [59]: log_files = !ls -l dpkg.log*
    
    In [60]: log_files[0]
    Out[60]: '-rw-r--r-- 1 root root   1824 нояб.  3 16:41 dpkg.log'
    
    In [61]: for line in log_files:
       ....:     size += int(line.split()[4])
       ....:     
    
    In [62]: size
    Out[62]: 1330009
    
    # ... или последовательно пингануть десяток хостов
    
    In [67]: for i in range(100,110):
       ....:     !ping -c 1 192.168.0.$i
       ....: 
    
    


    Остальные

    Конечно это не полный список даже популярных оболочек. Помимо вышеперечисленных категорий существуют ещё использующие собственный синтаксис, не совместимый с sh и не копирующий существующие ЯП. Примером может служить friendly interactive shell (fish). Но на последок хотел бы рассказать не о ней, а более специфической sleepshell.

    Sleep Dummy Shell, исполняемый файл: sleepshell. Строго говоря командным процессором sleepshell назвать нельзя, т.к. он не умеет обрабатывать команды. И вообще не умеет ничего, кроме как периодически записывать в стандартный вывод звёздочки "*". Однако используется она именно в качестве командной оболочки и вот для чего: Допустим мы хотим предоставить кому-то возможность делать тоннели ssh через наш сервер под управлением Linux или Unix. Подробнее про ssh-туннелирование читаем тут. Но нам не нужно при этом, что этот кто-то получил доступ к командной строке и файловой системе нашего сервера. Для такого случая и предназначена sleepshell. Создаем на сервере аккаунт в качестве шела для него устанавливаем sleepshell. Владелец аккаунта сможет подключаться и пробрасывать порты, но не сможет выполнять команды.

    На этом всё. Надеюсь, что было интересно. Буду рад любым замечаниям и советам по тексту статьи.

    Ссылки по теме

    www.faqs.org/faqs/unix-faq/shell/shell-differences — сводная таблица различий и сходств командных оболочек
    www.mariovaldez.net/software/sleepshell — Sleep Dummy Shell
    ipython.org/ipython-doc/dev/interactive/shell.html — IPython as a system shell
    www.opennet.ru/base/dev/ipython_sysadmin.txt.html — Оболочка IPython как инструмент системного администратора
    www.focusresearch.com/gregor/document/psh-1.8.1.html — документация по Perl Shell
    www.scsh.net — Scsh home page
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 33

      +1
      python и bash — повседневное использование, вместо IPython использую стандарный пакет
        +4
        Что-то так и не понял назначение Sleep Dummy Shell
        Указанный запрет доступа к командной строке достигается ключом -N самого ssh, либо /bin/false или /bin/nologin в качестве шелла
          +5
          сам не пробовал, но на сайте sleepshell пишут:
          Setting the account shell to something like /bin/false (or any other simple programs) usually won't work because the tunnel is closed as soon as the program finish its execution. Sleep Dummy Shell just sleeps until its execution is terminated by the user or the tunnel is closed.
            +1
            Так а в чем приемущество «спящего» шела, если ничего кроме как проброса порта не доступно в обоих вариантах?
              +4
              sleepshell приглашение печатает c адресами, портами и именем терминала
              и звездочки еще, красиво и keep alive своего рода

              прошу прощения, если мой вопрос глуп, но /bin/false должен же завершиться сразу после запуска и ssh сессия развалится?
                +1
                Вариант с ssh -N не подходит, т.к. сторонний пользователь может использовать этот ключ, а может и не использовать — и тогда получит командную строку. Если указать в профиле пользователя что-то нечленораздельное вроде /bin/nothing, то не получится сделать вообще ничего, т.к. сессия будет мгновенно закрываться.
            +5
            Кто-нибудь пользуется rush (ruby shell)?
              0
              а почему не остановились на zsh? Хотя бы ссылку на конфиги GRML приожили бы, ведь одна из мощных оболочек для режима интерпретатора
                0
                Groovy Shell for the win (-:
                  +1
                  Примеры для IPython слабоваты: не показывают преимуществ пред bash. Вот пример последовательного пинга 10 хостов на bash:
                  ~$ for i in `seq 100 110`; do ping -c 1 192.168.0.$i; done
                  
                    +3
                    Rush или просто irb (Interactive Ruby):

                    (100..110).each { |n| `ping -c 1 192.168.0.#{n}` }
                    
                      +1
                      Пример (и у вас и у ниже отписавшегося akzhan) не эквивалентен тому, что наверху: в Python range(n, n+k) возвращает [n, n+1, …, n+k-1]. Не […, n+k].

                      Ipython — просто штука, в которой иногда удобно по‐быстрому проверить работоспособность кода на Python. Ещё хорошо использовать как калькулятор. Возможность вызывать оболочку — просто приятное дополнение.
                      Соответственно преимущества перед bash — те же, что и у самого Python. Преимущества именно как замены /bin/bash в /etc/passwd — отсутствуют, он даже не дополняет команды из $PATH, только имена файлов.
                        0
                        тогда достаточно написать

                        (100...110) # как раз диапазон с исключением правой границы.
                        
                          0
                          А вообще — вы правы. Нет преимуществ реальных. Поэтому я использую bash.
                          +7
                          Не устаю пропагандировать xargs:

                          seq 100 110|xargs -n 1 -I ADDR ping -c 192.168.0.ADDR
                          

                          которая лёгким движением руки становится многопоточной:
                          seq 100 110|xargs -P 10 -n 1 -I ADDR ping -c 192.168.0.ADDR
                          

                            +1
                            Изящно. Про параллельны вариант не знал…
                            Но xargs — это механизм скриптинга под sh-совместимые оболочки, а я пытался показать как нам сделать все кроме ping на питоне. Если выбирать любой инструмент, то лучшим выбором имхо был бы «nmap -sP 192.168.0.100-110», и параллельно и вывод симпатичнее
                              0
                              Не работает:
                              ~$ seq 100 110|xargs -n 1 -I ADDR ping -c 192.168.0.ADDR
                              Usage: ping [-LRUbdfnqrvVaAD] [-c count] [-i interval] [-w deadline]
                                          [-p pattern] [-s packetsize] [-t ttl] [-I interface]
                              ...
                              
                                0
                                Полагаю автор имел ввиду $seq 100 110|xargs -n 1 -I ADDR ping -c 1 192.168.0.ADDR
                                  0
                                  А самому поправить? Видно же, что у ping у опции -c пропущен аргумент.
                                0
                                Согласен, примеры похоже не самые удачные. Придумывал такие, чтоб покороче, попроще…
                                Но, субъективное преимущество перед bash: есть много людей, которые знают Python, и им будет проще на нем и писать, чем запоминать, как правило не очевидные, конструкции bash.
                                И, субъективное преимущество перед Python: лаконичность выполнения системных команд. Сравните
                                >>> import os
                                >>> l = os.popen("ls -l").read()
                                
                                и
                                l = !ls -l
                                

                                  0
                                  Ну раз уж про bash, то и пользоваться башевым генератором последовательностей:
                                  for i in {100..110}; do ping -c 1 192.168.0.$i; done
                                  
                                  +5
                                  Наброшу немного про why not csh: www.faqs.org/faqs/unix-faq/shell/csh-whynot/
                                    0
                                    Отличный метод изучить некоторые трюки баша. Спасибо.
                                    0
                                    А нет ли шела, с так скажем cisco like дополнением? Т.е. когда вместо «show ip route» пишется «sh ip ro», и нет необходимости нажимать Tab для дополнения каждого слова, система автоматически находит если сокращение однозначно.
                                      0
                                      В zsh для директорий такое есть.
                                        0
                                        Не думаю, что это вообще возможно.
                                        В CLI cisco мы вводим именно команды и единый интерпретатор отвечает за их разбор, а в linux первое слово — это, как правило, название программы, а остальные — ее параметры и как с ними работать программа решает сама.
                                        К слову, iproute2 поддерживает нечто подобное.
                                        Вместо
                                        ~$ ip address add 
                                        
                                        можно написать
                                        ~$ ip a a
                                        

                                          0
                                          hg поддерживает для всех команд

                                          hg st вместо hg status
                                        0
                                        Интересно, консоль в стиле Quake — чисто гуевая или что-то консольное с прикрученным плюшками?

                                        И странно, почему забыли консольки типа ios cli (cisco) — помнится, что ios у нас на линуксе, а junos на BSD — несколько лет назад умельцы в Украине чисто ради веселья воткнули на juniper какой-то из графических толи WM, толи DE, врать не буду, но верю, что это в принципе возможно — тот же cico ACS или vmware venter — linux based, о чем честно пишется при запуске машин. При соответствующем вмешательстве в скрипты запуска и там и там можно получить не относящиеся к основному функционалу плюшки.
                                          0
                                          iOS уже тоже на BSD, т.к. сейчас так называется уже ОС установленная на iPhon/iPad/iTouch
                                          А Cisco IOS на сколько я помню не имеет к Unix\Linux отношения. Во всяком случае что в Cisco IOS что в Junos CLI нельзя назвать системной командной оболочкой. Это принципиально другое. Помню, на каких-то сетевых устройствах (не Cisco и не Juniper), была даже команда, чтоб из собственного CLI вывалится в системный shell.
                                            0
                                            Под OS X есть терминал в стиле квейковой консоли. Верней плагин к стандартному терминалу.
                                            +1
                                            На С# в Linux можно тоже скрипты писать:

                                            gluttton@lx:~> cat > script.sh << EOF
                                            > #!/usr/bin/csharp
                                            > 
                                            > System.Console.WriteLine ("Bingo!");
                                            > EOF
                                            gluttton@lx:~> chmod +x script.sh
                                            gluttton@lx:~> ./script.sh 
                                            Bingo!
                                            gluttton@lx:~>
                                            
                                              0
                                              ГРЕШНОВАТО!
                                                +1
                                                Не более чем писать в начале скриптов:
                                                #!/bin/sh
                                                

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

                                            Самое читаемое