Лекция №20 Интерпретатор bash
Начиная с этой лекции мы будем говорить о командном интерпретаторе bash (”баш“), который является потомком самого первого интерпретатора - sh или shell (”шелл“). Иногда говоря shell подразумевают bash, а говоря bash подразумевают shell. Разница между этими названиями иногда весьма условная.Мы же будем говорить именно о bash (Bourne again Shell).
Все это время мы работали в системе через командный интерпретатор bash. Или другими словами, мы взаимодействовали с системой через интерпретатор bash. Это так называемый интерактивный режим работы с системой. Кроме этого можно взаимодействовать с системой с помощью скриптов. Скрипт - представляет собой текстовый файл, в котором последовательно выполняются какие либо действия (программы, команды, другие скрипты). Если необходимо каждый день выполнять какие либо действия (например архивацию данных и копирование их на резервный сервер), то удобно записать такие действия в виде скрипта и затем вызывать только имя скрипта (или автоматизировать работу с помощью демона cron).
Каким образом bash понимает, что перед ним скрипт, а не простой текстовый файл? Если помните, то в Linux нет понятия расширения файла, и хотя для удобства некоторые называют файлы скриптов в виде *.sh, для интерпретатора это не имеет никакого значения. Основной указатель находится внутри файла. Когда вы запускаете программу, выполняете команду или скрипт, bash начинает анализировать первые символы файла в первой строке. Если bash встречает в начале символы ELF (Executable and Linkable Format), то это значит, что файл является скомпилированным файлом программой (аналог exe-файлов в Windows). Если первые символы в файле будут #!, то bash делает следующее. Берет остальные символы после #! и до конца строки (символа перевода на новую строку), через пробел добавляет имя последней команды (то есть имя скрипта) и выполняет полученную команду. Возможно сразу сложно разложить по полочкам, поэтому давайте на примере (нам понадобятся две консоли).
Наберите в текстовом редакторе следующий текст:
#!/bin/bash
sleep 100
Сохраните файл допустим с именем sleep.sh и не забудьте сделать его исполняемым (установить бит x):
igor@ubuntu:~/linux$ chmod u+x sleep.sh
Теперь запустим этот файл на исполнение:
igor@ubuntu:~/linux$ ./sleep.sh
Теперь во второй консоли выполните команду:
igor@ubuntu:~$ ps ax | grep bash
4861 pts/0 Ss 0:00 bash
4955 pts/1 Ss 0:00 bash
5011 pts/0 S+ 0:00 /bin/bash ./sleep.sh
Посмотрите на примере на процесс с PID 5011 - /bin/bash ./sleep.sh. bash взял символы первой строки после #!, а это /bin/bash и через пробел добавил имя последней команды - ./sleep.sh и запустил полученную конструкцию /bin/bash ./sleep.sh в виде отдельного процесса.
Чтобы стало еще понятнее измените содержание файла sleep.sh на следующее:
#!/bin/ls -l
и выполните скрипт:
igor@ubuntu:~/linux$ ./sleep.sh
-rwxr–r– 1 igor igor 13 2009-12-15 22:04 ./sleep.sh
Надеюсь, вам понятно почему именно такой результат выполнения полученного скрипта.
В большинстве случаев после #! указывается полный пусть к интерпретатору для которого написан скрипт. Например, если текст содержащийся в скрипте написан на языке perl, то первая строка будет выглядеть как #!/usr/bin/perl . Так как мы изучаем bash, то в наших примерах эта строка будет такой как в первом примере: #!/bin/bash . В зависимости от дистрибутива у вас могут быть установлены и другие интерпретаторы (например sh, dash, csh и т.д.). Интерпретатор sh является более старым, более простым и считается, что более быстрым чем bash. Конфигурационные скрипты системы могут начинаться со строки #!/bin/sh и если в системе не установлен интерпретатор sh, создают символическую ссылку в каталоге /bin с именем sh, которая ссылается на существующий интерпретатор (например тот же bash). Делается это для того, чтобы не переписывать первую строку #!/bin/sh у всех существующих в системе скриптов.
Чтобы определить некоторую информацию об исполняемом файле интерпретатора (и не только интерпретатора) можно воспользоваться следующими тремя командами: type, file и ldd. Команда type покажет где bash находит исполняемый файла той или иной команды, file покажет тип файла (скрипт, ELF и т.д.), ldd - покажет какие библиотеки необходимы для работы ELF-файла.
igor@ubuntu:~/linux$ type bash
bash является /bin/bash
igor@ubuntu:~/linux$ file /bin/bash
/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
igor@ubuntu:~/linux$ ldd /bin/bash
linux-gate.so.1 => (0×00375000)
libncurses.so.5 => /lib/libncurses.so.5 (0×00db1000)
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0×00ba8000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0×00210000)
/lib/ld-linux.so.2 (0×001f3000)
А вот пример с символической ссылкой:
SLES:~ # type sh
sh is /bin/sh
SLES:~ # file /bin/sh
/bin/sh: symbolic link to `bash’
Как раз тот случай, когда sh, это bash.
Теперь поговорим о потоках ввода/вывода.
Далее на лекции был разговор о потоках ввода/вывода. Вопрос этот не простой, преподаватель много говорил, рисовал схемы, все записать не успевал, поэтому, чтобы не терять время на восстановление этой темы предлагаю прочесть очень хорошее описание потоков в этой статье (автору - спасибо). Хотя достаточно будет прочесть раздел “Потоки и файлы” (это как раз то, что нам рассказывали на лекции), но рекомендую ознакомиться со статей полностью.
На следующей лекции продолжим знакомство с bash уже как с языком программирования и начнем рассматривать его основные конструкции.
Dimon:
кстати “#!” называется “sha-bang”
Ответить
31 июля 2010, 10:06