Документация bash
| Документация DHTML | Документация Smarty | SVG/VML Графика и JavaScript
| Документация bash |
- Содержание
- Часть 1. Введение
- Часть 2. Основы
- Часть 3. Углубленный материал
-
- 9. К вопросу о переменных
- 10. Циклы и ветвления
-
- 10.1. Циклы
- 10.2. Вложенные циклы
- 10.3. Управление ходом выполнения цикла
- 10.4. Операторы выбора
- 11. Внутренние команды
- 12. Внешние команды, программы и утилиты
-
- 12.1. Базовые команды
- 12.2. Более сложные команды
- 12.3. Команды для работы с датой и временем
- 12.4. Команды обработки текста
- 12.5. Команды для работы с файлами и архивами
- 12.6. Команды для работы с сетью
- 12.7. Команды управления терминалом
- 12.8. Команды выполнения математических операций
- 12.9. Прочие команды
- 13. Команды системного администрирования
- 14. Подстановка команд
- 15. Арифметические подстановки
- 16. Перенаправление ввода/вывода
-
- 16.1. С помощью команды exec
- 16.2. Перенаправление для блоков кода
- 16.3. Область применения
- 17. Встроенные документы
- Часть 4. Материал повышенной сложности
-
- 18. Регулярные выражения
- 19. Подоболочки, или Subshells
- 20. Ограниченный режим командной оболочки
- 21. Подстановка процессов
- 22. Функции
- 23. Псевдонимы
- 24. Списки команд
- 25. Массивы
- 26. Файлы
- 27. /dev и /proc
- 28. /dev/zero и /dev/null
- 29. Отладка сценариев
- 30. Необязательные параметры (ключи)
- 31. Широко распространенные ошибки
- 32. Стиль программирования
- 33. Разное
-
- 33.1. Интерактивный и неинтерактивный режим работы
- 33.2. Сценарии-обертки
- 33.3. Операции сравнения: Альтернативные решения
- 33.4. Рекурсия
- 33.5. "Цветные" сценарии
- 33.6. Оптимизация
- 33.7. Разные советы
- 33.8. Проблемы безопасности
- 33.9. Проблемы переносимости
- 33.10. Сценарии командной оболочки под Windows
- 34. Bash, версия 2
- 35. Замечания и дополнения
-
- 35.1. От автора
- 35.2. Об авторе
- 35.3. Инструменты, использовавшиеся при создании книги
-
- 35.3.1. Аппаратура
- 35.3.2. Программное обеспечение
- 35.4. Благодарности
- Литература
- A. Дополнительные примеры сценариев
- B. Маленький учебник по Sed и Awk
- C. Коды завершения, имеющие предопределенный смысл
- D. Подробное введение в операции ввода-вывода и перенаправление ввода-вывода
- E. Локализация
- F. История команд
- G. Пример файла .bashrc
- H. Преобразование пакетных (*.bat) файлов DOS в сценарии командной оболочки
- I. Упражнения
-
- I.1. Анализ сценариев
- I.2. Создание сценариев
- J. Авторские права
- Перечень таблиц
- 11-1. Идентификация заданий
- 30-1. Ключи Bash
- 33-1. Числовые значения цвета в escape-последовательностях
- B-1. Основные операции sed
- B-2. Примеры операций в sed
- C-1. "Зарезервированные" коды завершения
- H-1. Ключевые слова/переменные/операторы пакетных файлов DOS и их аналоги командной оболочки
- H-2. Команды DOS и их эквиваленты в UNIX
- Перечень приложений
- 2-1. cleanup: Сценарий очистки лог-файлов в /var/log
- 2-2. cleanup: Расширенная версия предыдущего сценария.
- 3-1. Вложенные блоки и перенаправление ввода-вывода
- 3-2. Сохранение результата исполнения вложенного блока в файл
- 3-3. Запуск цикла в фоновом режиме
- 3-4. Резервное архивирование всех файлов, которые были изменены в течение последних суток
- 4-1. Присваивание значений переменным и подстановка значений переменных
- 4-2. Простое присваивание
- 4-3. Присваивание значений переменным простое и замаскированное
- 4-4. Целое число или строка?
- 4-5. Позиционные параметры
- 4-6. wh, whois выяснение имени домена
- 4-7. Использование команды shift
- 5-1. Вывод "причудливых" переменных
- 5-2. Экранированные символы
- 6-1. завершение / код завершения
- 6-2. Использование символа ! для логической инверсии кода возврата
- 7-1. Что есть "истина"?
- 7-2. Эквиваленты команды test -- /usr/bin/test, [ ], и /usr/bin/[
- 7-3. Арифметические выражения внутри (( ))
- 7-4. Проверка "битых" ссылок
- 7-5. Операции сравнения
- 7-6. Проверка -- является ли строка пустой
- 7-7. zmost
- 8-1. Наибольший общий делитель
- 8-2. Арифметические операции
- 8-3. Построение сложных условий, использующих && и ||
- 8-4. Различные представления числовых констант
- 9-1. $IFS и пробельные символы
- 9-2. Ограничения времени ожидания ввода
- 9-3. Еще один пример ограничения времени ожидания ввода от пользователя
- 9-4. Ограничение времени ожидания команды read
- 9-5. Я -- root?
- 9-6. arglist: Вывод списка аргументов с помощью переменных $* и $@
- 9-7. Противоречия в переменных $* и $@
- 9-8. Содержимое $* и $@, когда переменная $IFS -- пуста
- 9-9. Переменная "подчеркивание"
- 9-10. Вставка пустых строк между параграфами в текстовом файле
- 9-11. Преобразование графических файлов из одного формата в другой, с изменением имени файла
- 9-12. Альтернативный способ извлечения подстрок
- 9-13. Подстановка параметров и сообщения об ошибках
- 9-14. Подстановка параметров и сообщение о "порядке использования"
- 9-15. Длина переменной
- 9-16. Поиск по шаблону в подстановке параметров
- 9-17. Изменение расширений в именах файлов:
- 9-18. Поиск по шаблону при анализе произвольных строк
- 9-19. Поиск префиксов и суффиксов с заменой по шаблону
- 9-20. Объявление переменных с помощью инструкции declare
- 9-21. Косвенные ссылки
- 9-22. Передача косвенных ссылок в awk
- 9-23. Генерация случайных чисел
- 9-24. Выбор случайной карты из колоды
- 9-25. Имитация бросания кубика с помощью RANDOM
- 9-26. Переустановка RANDOM
- 9-27. Получение псевдослучайных чисел с помощью awk
- 9-28. Работа с переменными в стиле языка C
- 10-1. Простой цикл for
- 10-2. Цикл for с двумя параметрами в каждом из элементов списка
- 10-3. Fileinfo: обработка списка файлов, находящегося в переменной
- 10-4. Обработка списка файлов в цикле for
- 10-5. Цикл for без списка аргументов
- 10-6. Создание списка аргументов в цикле for с помощью операции подстановки команд
- 10-7. grep для бинарных файлов
- 10-8. Список всех пользователей системы
- 10-9. Проверка авторства всех бинарных файлов в текущем каталоге
- 10-10. Список символических ссылок в каталоге
- 10-11. Список символических ссылок в каталоге, сохраняемый в файле
- 10-12. C-подобный синтаксис оператора цикла for
- 10-13. Работа с командой efax в пакетном режиме
- 10-14. Простой цикл while
- 10-15. Другой пример цикла while
- 10-16. Цикл while с несколькими условиями
- 10-17. C-подобный синтаксис оформления цикла while
- 10-18. Цикл until
- 10-19. Вложенный цикл
- 10-20. Команды break и continue в цикле
- 10-21. Прерывание многоуровневых циклов
- 10-22. Передача управление в начало внешнего цикла
- 10-23. Живой пример использования "continue N"
- 10-24. Использование case
- 10-25. Создание меню с помощью case
- 10-26. Оператор case допускает использовать подстановку команд вместо анализируемой переменной
- 10-27. Простой пример сравнения строк
- 10-28. Проверка ввода
- 10-29. Создание меню с помощью select
- 10-30. Создание меню с помощью select в функции
- 11-1. printf в действии
- 11-2. Ввод значений переменных с помощью read
- 11-3. Пример использования команды read без указания переменной для ввода
- 11-4. Ввод многострочного текста с помощью read
- 11-5. Обнаружение нажатия на курсорные клавиши
- 11-6. Чтение командой read из файла через перенаправление
- 11-7. Смена текущего каталога
- 11-8. Команда let, арифметические операции.
- 11-9. Демонстрация команды eval
- 11-10. Принудительное завершение сеанса
- 11-11. Шифрование по алгоритму "rot13"
- 11-12. Замена имени переменной на ее значение, в исходном тексте программы на языке Perl, с помощью eval
- 11-13. Установка значений аргументов с помощью команды set
- 11-14. Изменение значений позиционных параметров (аргументов)
- 11-15. "Сброс" переменной
- 11-16. Передача переменных во вложенный сценарий awk, с помощью export
- 11-17. Прием опций/аргументов, передаваемых сценарию, с помощью getopts
- 11-18. "Подключение" внешнего файла
- 11-19. Пример (бесполезный) сценария, который подключает себя самого.
- 11-20. Команда exec
- 11-21. Сценарий, который запускает себя самого
- 11-22. Ожидание завершения процесса перед тем как продолжить работу
- 11-23. Сценарий, завершающий себя сам с помощью команды kill
- 12-1. Создание оглавления диска для записи CDR, с помощью команды ls
- 12-2. Badname, удаление файлов в текущем каталоге, имена которых содержат недопустимые символы и пробелы.
- 12-3. Удаление файла по его номеру inode
- 12-4. Использование команды xargs для мониторинга системного журнала
- 12-5. copydir, копирование файлов из текущего каталога в другое место, с помощью xargs
- 12-6. Пример работы с expr
- 12-7. Команда date
- 12-8. Частота встречаемости отдельных слов
- 12-9. Какие из файлов являются сценариями?
- 12-10. Генератор 10-значных случайных чисел
- 12-11. Мониторинг системного журнала с помощью tail
- 12-12. Сценарий-эмулятор "grep"
- 12-13. Поиск слов в словаре
- 12-14. toupper: Преобразование символов в верхний регистр.
- 12-15. lowercase: Изменение имен всех файлов в текущем каталоге в нижний регистр.
- 12-16. du: Преобразование текстового файла из формата DOS в формат UNIX.
- 12-17. rot13: Сверхслабое шифрование по алгоритму rot13.
- 12-18. Более "сложный" шифр
- 12-19. Отформатированный список файлов.
- 12-20. Пример форматирования списка файлов в каталоге
- 12-21. nl: Самонумерующийся сценарий.
- 12-22. Пример перемещения дерева каталогов с помощью cpio
- 12-23. Распаковка архива rpm
- 12-24. Удаление комментариев из файла с текстом программы на языке C
- 12-25. Исследование каталога /usr/X11R6/bin
- 12-26. "Расширенная" команда strings
- 12-27. Пример сравнения двух файлов с помощью cmp.
- 12-28. Утилиты basename и dirname
- 12-29. Проверка целостности файла
- 12-30. Декодирование файлов
- 12-31. Сценарий, отправляющий себя самого по электронной почте
- 12-32. Ежемесячные выплаты по займу
- 12-33. Перевод чисел из одной системы счисления в другую
- 12-34. Пример взаимодействия bc со "встроенным документом"
- 12-35. Вычисление числа "пи"
- 12-36. Преобразование чисел из десятичной в шестнадцатиричную систему счисления
- 12-37. Разложение числа на простые множители
- 12-38. Расчет гипотенузы прямоугольного треугольника
- 12-39. Использование seq для генерации списка аргументов цикла for
- 12-40. Использование getopt для разбора аргументов командной строки
- 12-41. Захват нажатых клавиш
- 12-42. Надежное удаление файла
- 12-43. Генератор имен файлов
- 12-44. Преобразование метров в мили
- 12-45. Пример работы с m4
- 13-1. Установка символа "забоя"
- 13-2. невидимый пароль: Отключение эхо-вывода на терминал
- 13-3.
- 13-4. Использование команды pidof при остановке процесса
- 13-5. Проверка образа CD
- 13-6. Создание файловой системы в обычном файле
- 13-7. Добавление нового жесткого диска
- 13-8. Сценарий killall, из каталога /etc/rc.d/init.d
- 14-1. Глупая выходка
- 14-2. Запись результатов выполнения цикла в переменную
- 16-1. Перенаправление stdin с помощью exec
- 16-2. Перенаправление stdout с помощью exec
- 16-3. Одновременное перенаправление устройств, stdin и stdout, с помощью команды exec
- 16-4. Перенаправление в цикл while
- 16-5. Альтернативная форма перенаправления в цикле while
- 16-6. Перенаправление в цикл until
- 16-7. Перенаправление в цикл for
- 16-8. Перенаправление устройств (stdin и stdout) в цикле for
- 16-9. Перенаправление в конструкции if/then
- 16-10. Файл с именами "names.data", для примеров выше
- 16-11. Регистрация событий
- 17-1. dummyfile: Создание 2-х строчного файла-заготовки
- 17-2. broadcast: Передача сообщения всем, работающим в системе, пользователям
- 17-3. Вывод многострочных сообщений с помощью cat
- 17-4. Вывод многострочных сообщений с подавлением символов табуляции
- 17-5. Встроенные документы и подстановка параметров
- 17-6. Отключение подстановки параметров
- 17-7. Передача пары файлов во входящий каталог на "Sunsite"
- 17-8. Встроенные документы и функции
- 17-9. "Анонимный" Встроенный Документ
- 17-10. Блочный комментарий
- 17-11. Встроенная справка к сценарию
- 19-1. Область видимости переменных
- 19-2. Личные настройки пользователей
- 19-3. Запуск нескольких процессов в подоболочках
- 20-1. Запуск сценария в ограниченном режиме
- 22-1. Простая функция
- 22-2. Функция с аргументами
- 22-3. Наибольшее из двух чисел
- 22-4. Преобразование чисел в римскую форму записи
- 22-5. Проверка возможности возврата функциями больших значений
- 22-6. Сравнение двух больших целых чисел
- 22-7. Настоящее имя пользователя
- 22-8. Область видимости локальных переменных
- 22-9. Использование локальных переменных при рекурсии
- 23-1. Псевдонимы в сценарии
- 23-2. unalias: Объявление и удаление псевдонимов
- 24-1. Проверка аргументов командной строки с помощью "И-списка"
- 24-2. Еще один пример проверки аргументов с помощью "И-списков"
- 24-3. Комбинирование "ИЛИ-списков" и "И-списков"
- 25-1. Простой массив
- 25-2. Форматирование стихотворения
- 25-3. Некоторые специфичные особенности массивов
- 25-4. Пустые массивы и пустые элементы
- 25-5. Копирование и конкатенация массивов
- 25-6. Старая, добрая: "Пузырьковая" сортировка
- 25-7. Вложенные массивы и косвенные ссылки
- 25-8. Пример реализации алгоритма Решето Эратосфена
- 25-9. Эмуляция структуры "СТЕК" ("первый вошел -- последний вышел")
- 25-10. Исследование математических последовательностей
- 25-11. Эмуляция массива с двумя измерениями
- 27-1. Поиск файла программы по идентификатору процесса
- 27-2. Проверка состояния соединения
- 28-1. Удаление cookie-файлов
- 28-2. Создание файла подкачки (swapfile), с помощью /dev/zero
- 28-3. Создание электронного диска
- 29-1. Сценарий, содержащий ошибку
- 29-2. Пропущено ключевое слово
- 29-3. test24
- 29-4. Проверка условия с помощью функции "assert"
- 29-5. Ловушка на выходе
- 29-6. Удаление временного файла при нажатии на Control-C
- 29-7. Трассировка переменной
- 31-1. Западня в подоболочке
- 31-2. Передача вывода от команды echo команде read, по конвейеру
- 33-1. сценарий-обертка
- 33-2. Более сложный пример сценария-обертки
- 33-3. Сценарий-обертка вокруг сценария awk
- 33-4. Сценарий на языке Perl, встроенный в Bash-скрипт
- 33-5. Комбинирование сценария Bash и Perl в одном файле
- 33-6. Сценарий (бесполезный), который вызывает себя сам
- 33-7. Сценарий имеющий практическую ценность), который вызывает себя сам
- 33-8. "Цветная" адресная книга
- 33-9. Вывод цветного текста
- 33-10. Необычный способ передачи возвращаемого значения
- 33-11. Необычный способ получения нескольких возвращаемых значений
- 33-12. Передача массива в функцию и возврат массива из функции
- 33-13. Игры с анаграммами
- 34-1. Расширение строк
- 34-2. Косвенные ссылки на переменные -- новый метод
- 34-3. Простая база данных, с применением косвенных ссылок
- 34-4. Массивы и другие хитрости для раздачи колоды карт в четыре руки
- A-1. manview: Просмотр страниц руководств man
- A-2. mailformat: Форматирование электронных писем
- A-3. rn: Очень простая утилита для переименования файлов
- A-4. blank-rename: переименование файлов, чьи имена содержат пробелы
- A-5. encryptedpw: Передача файла на ftp-сервер, с использованием пароля
- A-6. copy-cd: Копирование компакт-дисков с данными
- A-7. Последовательности Коллаца (Collatz)
- A-8. days-between: Подсчет числа дней между двумя датами
- A-9. Создание "словаря"
- A-10. Расчет индекса "созвучности"
- A-11. "Игра "Жизнь""
- A-12. Файл с первым поколением для игры "Жизнь"
- A-13. behead: Удаление заголовков из электронных писем и новостей
- A-14. ftpget: Скачивание файлов по ftp
- A-15. Указание на авторские права
- A-16. password: Генератор случайного 8-ми символьного пароля
- A-17. fifo: Создание резервных копий с помощью именованных каналов
- A-18. Генерация простых чисел, с использованием оператора деления по модулю (остаток от деления)
- A-19. tree: Вывод дерева каталогов
- A-20. Функции для работы со строками
- A-21. Directory information
- A-22. Объектно ориентированная база данных
- G-1. Пример файла .bashrc
- H-1. VIEWDATA.BAT: пакетный файл DOS
- H-2. viewdata.sh: Результат преобразования VIEWDATA.BAT в сценарий командной оболочки
Часть 1. Введение
Shell -- это командная оболочка. Но это не просто промежуточное звено между пользователем и операционой системой, это еще и мощный язык программирования. Программы на языке shell называют сценариями, или скриптами. Фактически, из скриптов доступен полный набор команд, утилит и программ UNIX. Если этого недостаточно, то к вашим услугам внутренние команды shell -- условные операторы, операторы циклов и пр., которые увеличивают мощь и гибкость сценариев. Shell-скрипты исключительно хороши при программировании задач администрирования системы и др., которые не требуют для своего создания полновесных языков программирования.
- Содержание
- 1. Зачем необходимо знание языка Shell?
- 2. Для начала о Sha-Bang
-
- 2.1. Запуск сценария
- 2.2. Упражнения
Глава 1. Зачем необходимо знание языка Shell?
Знание языка командной оболочки является залогом успешного решения задач администрирования системы. Даже если вы не предполагаете заниматься написанием своих сценариев. Во время загрузки Linux выполняется целый ряд сценариев из /etc/rc.d, которые настраивают конфигурацию операционной системы и запускают различные сервисы, поэтому очень важно четко понимать эти скрипты и иметь достаточно знаний, чтобы вносить в них какие либо изменения.
Язык сценариев легок в изучении, в нем не так много специфических операторов и конструкций. [1] Синтаксис языка достаточно прост и прямолинеен, он очень напоминает команды, которые приходится вводить в командной строке. Короткие скрипты практически не нуждаются в отладке, и даже отладка больших скриптов отнимает весьма незначительное время.
Shell-скрипты очень хорошо подходят для быстрого создания прототипов сложных приложений, даже не смотря на ограниченный набор языковых конструкций и определенную "медлительность". Такая метода позволяет детально проработать структуру будущего приложения, обнаружить возможные "ловушки" и лишь затем приступить к кодированию на C, C++, Java, или Perl.
Скрипты возвращают нас к классической философии UNIX -- "разделяй и влавствуй" т.е. разделение сложного проекта на ряд простых подзадач. Многие считают такой подход наилучшим или, по меньшей мере, наиболее эстетичным способом решения возникающих проблем, нежели использование нового поколения языков -- "все-в-одном", таких как Perl.
Для каких задач неприменимы скрипты
-
для ресурсоемких задач, особенно когда важна скорость исполнения (поиск, сортировка и т.п.)
-
для задач, связанных с выполнением математических вычислений, особенно это касается вычислений с плавающей запятой, вычислений с повышенной точностью, комплексных чисел (для таких задач лучше использовать C++ или FORTRAN)
-
для кросс-платформенного программирования (для этого лучше подходит язык C)
-
для сложных приложений, когда структурирование является жизненной необходимостью (контроль за типами переменных, прототипами функций и т.п.)
-
для целевых задач, от которых может зависеть успех предприятия.
-
когда во главу угла поставлена безопасность системы, когда необходимо обеспечить целостность системы и защитить ее от вторжения, взлома и вандализма.
-
для проектов, содержащих компоненты, очень тесно взаимодействующие между собой.
-
для задач, выполняющих огромный объем работ с файлами
-
для задач, работающих с многомерными массивами
-
когда необходимо работать со структурами данных, такими как связанные списки или деревья
-
когда необходимо предоставить графический интерфейс с пользователем (GUI)
-
когда необходим прямой доступ к аппаратуре компьютера
-
когда необходимо выполнять обмен через порты ввода-вывода или сокеты
-
когда необходимо использовать внешние библиотеки
-
для проприетарных, "закрытых" программ (скрипты представляют из себя исходные тексты программ, доступные для всеобщего обозрения)
Если выполняется хотя бы одно из вышеперечисленных условий, то вам лучше обратиться к более мощным скриптовым языкам программирования, например Perl, Tcl, Python, Ruby или к высокоуровневым компилирующим языкам -- C, C++ или Java. Но даже в этом случае, создание прототипа приложения на языке shell может существенно облегчить разработку.
Название BASH -- это аббревиатура от "Bourne-Again Shell" и игра слов от, ставшего уже классикой, "Bourne Shell" Стефена Бурна (Stephen Bourne). В последние годы BASH достиг такой популярности, что стал стандартной командной оболочкой de facto для многих разновидностей UNIX. Большинство принципов программирования на BASH одинаково хорошо применимы и в других командных оболочках, таких как Korn Shell (ksh), от которой Bash позаимствовал некоторые особенности, [2] и C Shell и его производных. (Примечательно, что C Shell не рекомендуется к использованию из-за отдельных проблем, отмеченных Томом Кристиансеном (Tom Christiansen) в октябре 1993 года на Usenet post
Далее, в тексте документа вы найдете большое количество примеров скриптов, иллюстрирующих возможности shell. Все примеры -- работающие. Они были протестированы, причем некоторые из них могут пригодиться в повседневной работе. Уважаемый читатель можеть "поиграть" с рабочим кодом скриптов, сохраняя их в файлы, с именами scriptname.sh. [3] Не забудьте выдать этим файлам право на исполнение (chmod u+rx scriptname), после чего сценарии можно будет запустить на исполнение и проверить результат их работы. Вам следует помнить, что описание некоторых примеров следует после исходного кода этого примера, поэтому, прежде чем запустить сценарий у себя -- ознакомьтесь с его описанием.
Скрипты были написаны автором книги, если не оговаривается иное.
Глава 2. Для начала о Sha-Bang
В простейшем случае, скрипт -- это ни что иное, как простой список команд системы, записанный в файл. Создание скриптов поможет сохранить ваше время и силы, которые тратятся на ввод последовательности команд всякий раз, когда необходимо их выполнить.
Пример 2-1. cleanup: Сценарий очистки лог-файлов в /var/log
# cleanup # Для работы сценария требуются права root. cd /var/log cat /dev/null > messages cat /dev/null > wtmp echo "Лог-файлы очищены."
Здесь нет ничего необычного, это простая последовательность команд, которая может быть набрана в командной строке с консоли или в xterm. Преимущество размещения последовательности команд в скрипте состоит в том, что вам не придется всякий раз набирать эту последовательность вручную. Кроме того, скрипты легко могут быть модифицированы или обобщены для разных применений.
Пример 2-2. cleanup: Расширенная версия предыдущего сценария.
#!/bin/bash
# cleanup, version 2
# Для работы сценария требуются права root.
LOG_DIR=/var/log
ROOT_UID=0 # Только пользователь с $UID 0 имеет привилегии root.
LINES=50 # Количество сохраняемых строк по-умолчанию.
E_XCD=66 # Невозможно сменить каталог?
E_NOTROOT=67 # Признак отсутствия root-привилегий.
if [ "$UID" -ne "$ROOT_UID" ]
then
echo "Для работы сценария требуются права root."
exit $E_NOTROOT
fi
if [ -n "$1" ]
# Проверка наличия аргумента командной строки.
then
lines=$1
else
lines=$LINES # Значение по-умолчанию, если число не задано в командной строке
fi
# Stephane Chazelas предложил следующее,
#+ для проверки корректности аргумента, переданного из командной строки,
#+ правда это достаточно сложно для данного руководства.
#
# E_WRONGARGS=65 # Не числовой аргумент
#
# case "$1" in
# "" ) lines=50;;
# *[!0-9]*) echo "Usage: `basename $0` file-to-cleanup"; exit $E_WRONGARGS;;
# * ) lines=$1;;
# esac
#
#* Конец проверки корректности аргумента
cd $LOG_DIR
if [ `pwd` != "$LOG_DIR" ] # или if [ "$PWD" != "$LOG_DIR" ]
# Не в /var/log?
then
echo "Невозможно перейти в каталог $LOG_DIR."
exit $E_XCD
fi # Проверка каталога перед очисткой лог-файлов.
# более эффективный вариант:
#
# cd /var/log || {
# echo "Невозможно перейти в требуемый каталог." >&2
# exit $E_XCD;
# }
tail -$lines messages > mesg.temp # Сохранить последние строки в лог-файле.
mv mesg.temp messages
# cat /dev/null > messages
#* Необходимость этой команды отпала, поскольку очистка выполняется выше.
cat /dev/null > wtmp # команды ': > wtmp' и '> wtmp' имеют тот же эффект.
echo "Лог-файлы очищены."
exit 0
# Возвращаемое значение 0
#+ указывает на успешное завершение работы сценария.
Если вы не желаете полностью вычищать системные логи, то выше представлена улучшенная версия предыдущего сценария. Здесь сохраняются последние несколько строк (по-умолчанию -- 50).
Если файл сценария начинается с последовательности #!, которая в мире UNIX называется sha-bang, то это указывает системе какой интерпретатор следует использовать для исполнения сценария. Это двухбайтовая последовательность, или [4] -- специальный маркер, определяющий тип сценария, в данном случае -- сценарий командной оболочки (см. man magic). Более точно, sha-bang определяет интерпретатор, который вызывается для исполнения сценария, это может быть командная оболочка (shell), иной интерпретатор или утилита. [5]
#!/bin/sh #!/bin/bash #!/usr/bin/perl #!/usr/bin/tcl #!/bin/sed -f #!/usr/awk -f
Каждая, из приведенных выше сигнатур, приводит к вызову различных интерпретаторов, будь то /bin/sh -- командный интерпретатор по-умолчанию (bash для Linux-систем), либо иной. [6] При переносе сценариев с сигнатурой #!/bin/sh на другие UNIX системы, где в качестве командного интерпретатора задан другой shell, вы можете лишиться некоторых особенностей, присущих bash. Поэтому такие сценарии должны быть POSIX совместимыми. [7].
Обратите внимание на то, что сигнатура должна указывать правильный путь к интерпретатору, в противном случае вы получите сообщение об ошибке -- как правило это "Command not found".
Сигнатура #! может быть опущена, если вы не используете специфичных команд. Во втором примере (см. выше) использование сигнатуры #! обязательно, поскольку сценарий использует специфичную конструкцию присваивания значения переменной lines=50. Еще раз замечу, что сигнатура #!/bin/sh вызывает командный интерпретатор по-умолчанию -- /bin/bash в Linux-системах.
![]() |
В данном руководстве приветствуется модульный подход к построению сценариев. Записывайте, собирайте свою коллекцию участков кода, который может вам встретиться. В конечном итоге вы соберете свою "библиотеку" подпрограмм, которые затем сможете использовать при написании своих сценариев. Например, следующий отрывок сценария проверяет количество аргументов в командной строке: if [ $# -ne Number_of_expected_args ] then echo "Usage: `basename $0` whatever" exit $WRONG_ARGS fi |
2.1. Запуск сценария
Запустить сценарий можно командой sh scriptname [8] или bash scriptname. (Не рекомендуется запуск сценария командой sh <scriptname>, поскольку это запрещает использование устройства стандартного ввода stdin в скрипте). Более удобный вариант -- сделать файл скрипта исполняемым, командой chmod.
- Это:
-
chmod 555 scriptname (выдача прав на чтение/исполнение любому пользователю в системе) [9]
- или
-
chmod +rx scriptname (выдача прав на чтение/исполнение любому пользователю в системе)
chmod u+rx scriptname (выдача прав на чтение/исполнение только "владельцу" скрипта)
После того, как вы сделаете файл сценария исполняемым, вы можете запустить его примерно такой командой ./scriptname. [10] Если, при этом, текст сценария начинается с корректной сигнатуры ("sha-bang"), то для его исполнения будет вызван соответствующий интерпретатор.
И наконец, завершив отладку сценария, вы можете поместить его в каталог /usr/local/bin (естественно, что для этого вы должны обладать правами root), чтобы сделать его доступным для себя и других пользователей системы. После этого сценарий можно вызвать, просто напечатав название файла в командной строке и нажав клавишу [ENTER].
2.2. Упражнения
-
Системные администраторы часто создают скрипты для автоматизации своего труда. Подумайте, для выполнения каких задач могут быть написаны сценарии.
-
Напишите сценарий, который выводит дату, время, список зарегистрировавшихся пользователей, и uptime системы и сохраняет эту информацию в системном журнале.
Часть 2. Основы
- Содержание
- 3. Служебные символы
- 4. Переменные и параметры. Введение.
- 5. Кавычки
- 6. Завершение и код завершения
- 7. Проверка условий
- 8. Операции и смежные темы
-
- 8.1. Операторы
- 8.2. Числовые константы
Глава 3. Служебные символы
Служебные символы, используемые в текстах сценариев.
- #
-
Комментарии. Строки, начинающиеся с символа # (за исключением комбинации #!) -- являются комментариями.
# Эта строка -- комментарий.
Комментарии могут располагаться и в конце строки с исполняемым кодом.
echo "Далее следует комментарий." # Это комментарий.
Комментариям могут предшествовать пробелы (пробел, табуляция).
# Перед комментарием стоит символ табуляции.

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

Само собой разумеется, экранированный символ # в операторе echo не воспринимается как начало комментария. Более того, он может использоваться в операциях подстановки параметров и в константных числовых выражениях.
echo "Символ # не означает начало комментария." echo 'Символ # не означает начало комментария.' echo Символ \# не означает начало комментария. echo А здесь символ # означает начало комментария. echo ${PATH#*:} # Подстановка -- не комментарий. echo $(( 2#101011 )) # База системы счисления -- не комментарий. # Спасибо, S.C.Кавычки " ' и \ экранируют действие символа #.
В операциях поиска по шаблону символ # так же не воспринимается как начало комментария.
- ;
-
Разделитель команд. [Точка-с-запятой] Позволяет записывать две и более команд в одной строке.
echo hello; echo there
Следует отметить, что символ ";" иногда так же как и # необходимо экранировать.
- ;;
-
Ограничитель в операторе выбора case . [Двойная-точка-с-запятой]
case "$variable" in abc) echo "$variable = abc" ;; xyz) echo "$variable = xyz" ;; esac
- .
-
команда "точка". Эквивалент команды source (см. Пример 11-18). Это встроенная команда bash.
- .
-
"точка" может являться частью имени файла . Если имя файла начинается с точки, то это "скрытый" файл, т.е. команда ls при обычных условиях его не отображает.
bash$ touch .hidden-file bash$ ls -l total 10 -rw-r--r-- 1 bozo 4034 Jul 18 22:04 data1.addressbook -rw-r--r-- 1 bozo 4602 May 25 13:58 data1.addressbook.bak -rw-r--r-- 1 bozo 877 Dec 17 2000 employment.addressbook bash$ ls -al total 14 drwxrwxr-x 2 bozo bozo 1024 Aug 29 20:54 ./ drwx------ 52 bozo bozo 3072 Aug 29 20:51 ../ -rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.addressbook -rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.addressbook.bak -rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.addressbook -rw-rw-r-- 1 bozo bozo 0 Aug 29 20:54 .hidden-file
Если подразумевается имя каталога, то одна точка означает текущий каталог и две точки -- каталог уровнем выше, или родительский каталог.
bash$ pwd /home/bozo/projects bash$ cd . bash$ pwd /home/bozo/projects bash$ cd .. bash$ pwd /home/bozo/
Символ точка довольно часто используется для обозначения каталога назначения в операциях копирования/перемещения файлов.
bash$ cp /home/bozo/current_work/junk/* .
- .
-
Символ "точка" в операциях поиска. При выполнении поиска по шаблону , в регулярных выражениях, символ "точка" обозначает одиночный символ.
- "
-
Двойные кавычки . В строке "STRING", ограниченной двойными кавычками не выполняется интерпретация большинства служебных символов, которые могут находиться в строке. см. Глава 5.
- '
-
Одинарные кавычки . [Одинарные кавычки] 'STRING' экранирует все служебные символы в строке STRING. Это более строгая форма экранирования. Смотрите так же Глава 5.
- ,
-
Запятая . Оператор запятая используется для вычисления серии арифметических выражений. Вычисляются все выражения, но возвращается результат последнего выражения.
let "t2 = ((a = 9, 15 / 3))" # Присваивает значение переменной "a" и вычисляет "t2".
- \
-
escape. [обратный слэш] Комбинация \X "экранирует" символ X. Аналогичный эффект имеет комбинация с "одинарными кавычками", т.е. 'X'. Символ \ может использоваться для экранирования кавычек " и '.
Более детальному рассмотрению темы экранирования посвящена Глава 5.
- /
-
Разделитель, используемый в указании пути к каталогам и файлам. [слэш] Отделяет элементы пути к каталогам и файлам (например /home/bozo/projects/Makefile).
В арифметических операциях -- это оператор деления.
- `
-
Подстановка команд. [обратные кавычки] Обратные кавычки могут использоваться для записи в переменную команды `command`.
- :
-
пустая команда. [двоеточие] Это эквивалент операции "NOP" (no op, нет операции). Может рассматриваться как синоним встроенной команды true. Команда ":" так же является встроенной командой Bash, которая всегда возвращает "true" (0).
: echo $? # 0
Бесконечный цикл:
while : do operation-1 operation-2 ... operation-n done # То же самое: # while true # do # ... # done
Символ-заполнитель в условном операторе if/then:
if condition then : # Никаких действий не производится и управление передается дальше else take-some-action fi
Как символ-заполнитель в операциях, которые предполагают наличие двух операндов, см. Пример 8-2 и параметры по-умолчанию.
: ${username=`whoami`} # ${username=`whoami`} без символа : выдает сообщение об ошибке, # если "username" не является командой...
Как символ-заполнитель для оператора вложенного документа. См. Пример 17-9.
В операциях с подстановкой параметров (см. Пример 9-13).
: ${HOSTNAME?} ${USER?} ${MAIL?} #Вывод сообщения об ошибке, если одна или более переменных не определены.
В операциях замены подстроки с подстановкой значений переменных.
В комбинации с оператором > (оператор перенаправления вывода), усекает длину файла до нуля. Если указан несуществующий файл -- то он создается.
: > data.xxx # Файл "data.xxx" -- пуст # Тот же эффект имеет команда cat /dev/null >data.xxx # Однако в данном случае не производится создание нового процесса, поскольку ":" является встроенной командой.
См. так же Пример 12-11.
В комбинации с оператором >> -- оператор перенаправления с добавлением в конец файла и обновлением времени последнего доступа (: >> new_file). Если задано имя несуществующего файла, то он создается. Эквивалентно команде touch.

Вышеизложенное применимо только к обычным файлам и неприменимо к конвейерам, символическим ссылкам и другим специальным файлам.
Символ : может использоваться для создания комментариев, хотя и не рекомендуется. Если строка комментария начинается с символа #, то такая строка не проверяется интерпретатором на наличие ошибок. Однако в случае оператора : это не так.
: Это комментарий, который генерирует сообщение об ошибке, ( if [ $x -eq 3] ).
Символ ":" может использоваться как разделитель полей в /etc/passwd и переменной $PATH.
bash$ echo $PATH /usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games
- !
-
инверсия (или логическое отрицание) используемое в условных операторах. Оператор ! инвертирует код завершения команды, к которой он применен. (см. Пример 6-2). Так же используется для логического отрицания в операциях сравнения, например, операция сравнения "равно" ( = ), при использовании оператора отрицания, преобразуется в операцию сравнения -- "не равно" ( != ). Символ ! является зарезервированным ключевым словом BASH.
В некоторых случаях символ ! используется для косвенного обращения к переменным.
Кроме того, из командной строки оператор ! запускает механизм историй Bash (см. Приложение F). Примечательно, что этот механизм недоступен из сценариев (т.е. исключительно из командной строки).
- *
-
символ-шаблон. [звездочка] Символ * служит "шаблоном" для подстановки в имена файлов. Одиночный символ * означает любое имя файла в заданном каталоге.
bash$ echo * abs-book.sgml add-drive.sh agram.sh alias.sh
В регулярных выражениях токен * представляет любое количество (в том числе и 0) символов.
- *
-
арифметический оператор. В арифметических выражениях символ * обозначает операцию умножения.
Двойная звездочка (два символа звездочки, следующих подряд друг за другом -- **), обозначает операцию возведения в степень.
- ?
-
Оператор проверки условия. В некоторых выражениях символ ? служит для проверки выполнения условия.
В конструкциях с двойными скобками, символ ? подобен трехместному оператору языка C. См. Пример 9-28.
В выражениях с подстановкой параметра, символ ? проверяет -- установлена ли переменная.
- ?
-
сивол-шаблон. Символ ? обозначает одиночный символ при подстановке в имена файлов. В регулярных выражениях служит для обозначения одиночного символа.
- $
-
Символ $, предшествующий имени переменной, указывает на то, что будет получено значение переменной.
- $
-
end-of-line (конец строки). В регулярных выражениях, символ "$" обозначает конец строки.
- ${}
- $*, $@
- $?
-
код завершения. Переменная $? хранит код завершения последней выполненной команды, функции или сценария.
- $$
-
id процесса. Переменная $$ хранит id процесса сценария.
- ()
-
группа команд.
(a=hello; echo $a)

Команды, заключенные в круглые скобки исполняются в дочернем процессе -- subshell-е.
Переменные, создаваемые в дочернем процессе не видны в "родительском" сценарии. Родительский процесс-сценарий, не может обращаться к переменным, создаваемым в дочернем процессе.
a=123 ( a=321; ) echo "a = $a" # a = 123 # переменная "a" в скобках подобна локальной переменной.
инициализация массивов.
Array=(element1 element2 element3)
- {xxx,yyy,zzz,...}
-
Фигурные скобки.
grep Linux file*.{txt,htm*} # Поиск всех вхождений слова "Linux" # в файлах "fileA.txt", "file2.txt", "fileR.html", "file-87.htm", и пр.
Команда интерпретируется как список команд, разделенных точкой с запятой, с вариациями, представленными в фигурных скобках. [11] При интерпретации имен файлов (подстановка) используются параметры, заключенные в фигурные скобки.

Использование неэкранированных или неокавыченных пробелов внутри фигурных скобок недопустимо.
echo {file1,file2}\ :{\ A," B",' C'}
file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C
- {}
-
Блок кода. [фигурные скобки] Известен так же как "вложенный блок", эта конструкция, фактически, создает анонимную функцию. Однако, в отличии от обычных функций, переменные, создаваемые во вложенных блоках кода, доступны объемлющему сценарию.
bash$ { local a; a=123; } bash: local: can only be used in a function
a=123 { a=321; } echo "a = $a" # a = 321 (значение, присвоенное во вложенном блоке кода) # Спасибо, S.C.
Код, заключенный в фигурные скобки, может выполнять перенаправление ввода-вывода.
Пример 3-1. Вложенные блоки и перенаправление ввода-вывода
#!/bin/bash # Чтение строк из файла /etc/fstab. File=/etc/fstab { read line1 read line2 } < $File echo "Первая строка в $File :" echo "$line1" echo echo "Вторая строка в $File :" echo "$line2" exit 0Пример 3-2. Сохранение результата исполнения вложенного блока в файл
#!/bin/bash # rpm-check.sh # Запрашивает описание rpm-архива, список файлов, и проверяется возможность установки. # Результат сохраняется в файле. # # Этот сценарий иллюстрирует порядок работы со вложенными блоками кода. SUCCESS=0 E_NOARGS=65 if [ -z "$1" ] then echo "Порядок использования: `basename $0` rpm-file" exit $E_NOARGS fi { echo echo "Описание архива:" rpm -qpi $1 # Запрос описания. echo echo "Список файлов:" rpm -qpl $1 # Запрос списка. echo rpm -i --test $1 # Проверка возможности установки. if [ "$?" -eq $SUCCESS ] then echo "$1 может быть установлен." else echo "$1 -- установка невозможна!" fi echo } > "$1.test" # Перенаправление вывода в файл. echo "Результаты проверки rpm-архива находятся в файле $1.test" # За дополнительной информацией по ключам команды rpm см. man rpm. exit 0 - {} \;
-
pathname -- полное имя файла (т.е. путь к файлу и его имя). Чаще всего используется совместно с командой find.

Обратите внимание на то, что символ ";", которым завершается ключ -exec команды find, экранируется обратным слэшем. Это необходимо, чтобы предотвратить его интерпретацию.
- [ ]
-
test.
Проверка истинности выражения, заключенного в квадратные скобки [ ]. Примечательно, что [ является частью встроенной команды test (и ее синонимом), И не имеет никакого отношения к "внешней" утилите /usr/bin/test.
- [[ ]]
-
test.
Проверка истинности выражения, заключенного между [[ ]] (зарезервированное слово интерпретатора).
См. описание конструкции [[ ... ]] ниже.
- [ ]
-
элемент массива.
При работе с массивами в квадратных скобках указывается порядковый номер того элемента массива, к которому производится обращение.
Array[1]=slot_1 echo ${Array[1]}
- [ ]
-
диапазон символов.
В регулярных выражениях, в квадратных скобках задается диапазон искомых символов.
- (( ))
-
двойные круглые скобки.
Вычисляется целочисленное выражение, заключенное между двойными круглыми скобками (( )).
См. обсуждение, посвященное конструкции (( ... )) .
- > &> >& >> <
-
Конструкция scriptname >filename перенаправляет вывод scriptname в файл filename. Если файл filename уже существовал, то его прежнее содержимое будет утеряно.
Конструкция command &>filename перенаправляет вывод команды command, как со stdout, так и с stderr, в файл filename.
Конструкция command >&2 перенаправляет вывод со stdout на stderr.
Конструкция scriptname >>filename добавляет вывод scriptname к файлу filename. Если задано имя несуществующего файла, то он создается.
(command)>
<(command)
В операциях сравнения, символы "<" и ">" обозначают операции сравнения строк .
А так же -- операции сравнения целых чисел. См. так же Пример 12-6.
- <<
-
перенаправление ввода на встроенный документ.
- <, >
-
veg1=carrots veg2=tomatoes if [[ "$veg1" < "$veg2" ]] then echo "Не смотря на то, что в словаре слово $veg1 предшествует слову $veg2," echo "это никак не отражает мои кулинарные предпочтения." else echo "Интересно. Каким словарем вы пользуетесь?" fi
- \<, \>
-
bash$ grep '\<the\>' textfile
- |
-
конвейер. Передает вывод предыдущей команды на ввод следующей или на вход командного интерпретатора shell. Этот метод часто используется для связывания последовательности команд в единую цепочку.
echo ls -l | sh # Передает вывод "echo ls -l" команлному интерпретатору shell, #+ тот же результат дает простая команда "ls -l". cat *.lst | sort | uniq # Объединяет все файлы ".lst", сортирует содержимое и удаляет повторяющиеся строки.
Конвейеры (еще их называют каналами) -- это классический способ взаимодействия процессов, с помощью которого stdout одного процесса перенаправляется на stdin другого. Обычно используется совместно с командами вывода, такими как cat или echo, от которых поток данных поступает в "фильтр" (команда, которая на входе получает данные, преобразует их и обрабатывает).
cat $filename | grep $search_word
В конвейер могут объединяться и сценарии на языке командной оболочки.
#!/bin/bash # uppercase.sh : Преобразование вводимых символов в верхний регистр. tr 'a-z' 'A-Z' # Диапазоны символов должны быть заключены в кавычки #+ чтобы предотвратить порождение имен файлов от однобуквенных имен файлов. exit 0
А теперь попробуем объединить в конвейер команду ls -l с этим сценарием.bash$ ls -l | ./uppercase.sh -RW-RW-R-- 1 BOZO BOZO 109 APR 7 19:49 1.TXT -RW-RW-R-- 1 BOZO BOZO 109 APR 14 16:48 2.TXT -RW-R--R-- 1 BOZO BOZO 725 APR 20 20:56 DATA-FILE

Выход stdout каждого процесса в конвейере должен читаться на входе stdin последующим, в конвейере, процессом. Если этого не делается, то поток данных блокируется, в результате конвейер будет работать не так как ожидается.
cat file1 file2 | ls -l | sort # Вывод команды "cat file1 file2" будет утерян.
Конвейер исполняется в дочернем процессе, а посему -- не имеет доступа к переменным сценария.
variable="initial_value" echo "new_value" | read variable echo "variable = $variable" # variable = initial_value
Если одна из команд в конвейере завершается аварийно, то это приводит к аварийному завершению работы всего конвейера.
- >|
-
принудительное перенаправление, даже если установлен ключ noclobber option.
- ||
-
логическая операция OR (логическое ИЛИ). В опрециях проверки условий, оператор || возвращает 0 (success), если один из операндов имеет значение true (ИСТИНА).
- &
-
Выполнение задачи в фоне. Команда, за которой стоит &, будет исполняться в фоновом режиме.
bash$ sleep 10 & [1] 850 [1]+ Done sleep 10
В сценариях команды, и даже циклы могут запускаться в фоновом режиме.
Пример 3-3. Запуск цикла в фоновом режиме
#!/bin/bash # background-loop.sh for i in 1 2 3 4 5 6 7 8 9 10 # Первый цикл. do echo -n "$i " done & # Запуск цикла в фоне. # Иногда возможны случаи выполнения этого цикла после второго цикла. echo # Этот 'echo' иногда не отображается на экране. for i in 11 12 13 14 15 16 17 18 19 20 # Второй цикл. do echo -n "$i " done echo # Этот 'echo' иногда не отображается на экране. # ====================================================== # Ожидается, что данный сценарий выведет следующую последовательность: # 1 2 3 4 5 6 7 8 9 10 # 11 12 13 14 15 16 17 18 19 20 # Иногда возможен такой вариант: # 11 12 13 14 15 16 17 18 19 20 # 1 2 3 4 5 6 7 8 9 10 bozo $ # (Второй 'echo' не был выполнен. Почему?) # Изредка возможен такой вариант: # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # (Первый 'echo' не был выполнен. Почему?) # Крайне редко встречается и такое: # 11 12 13 1 2 3 4 5 6 7 8 9 10 14 15 16 17 18 19 20 # Второй цикл начал исполняться раньше первого. exit 0
Команда, исполняемая в пределах сценария в фоне, может подвесить сценарий, ожидая нажатия клавиши. К счастью, это легко "лечится".
- &&
-
Логическая операция AND (логическое И). В операциях проверки условий, оператор && возвращает 0 (success) тогда, и только тогда, когда оба операнда имеют значение true (ИСТИНА).
- -
-
префикс ключа. С этого символа начинаются опциональные ключи команд.
COMMAND -[Option1][Option2][...]
ls -al
sort -dfu $filename
set -- $variable
if [ $file1 -ot $file2 ] then echo "Файл $file1 был создан раньше чем $file2." fi if [ "$a" -eq "$b" ] then echo "$a равно $b." fi if [ "$c" -eq 24 -a "$d" -eq 47 ] then echo "$c равно 24, а $d равно 47." fi
- -
-
(cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -) # Перемещение полного дерева файлов и подкаталогов из одной директории в другую # [спасибо Алану Коксу (Alan Cox) <[email protected]>, за небольшие поправки] # 1) cd /source/directory Переход в исходный каталог, содержимое которого будет перемещено # 2) && "И-список": благодаря этому все последующие команды будут выполнены # только тогда, когда 'cd' завершится успешно # 3) tar cf - . ключом 'c' архиватор 'tar' создает новый архив, # ключом 'f' (file) и последующим '-' задается файл архива -- stdout, # в архив помещается текущий каталог ('.') с вложенными подкаталогами. # 4) | конвейер с ... # 5) ( ... ) subshell-ом (дочерним экземпляром командной оболочки) # 6) cd /dest/directory Переход в каталог назначения. # 7) && "И-список", см. выше # 8) tar xpvf - Разархивирование ('x'), с сохранением атрибутов "владельца" и прав доступа ('p') к файлам, # с выдачей более подробных сообщений на stdout ('v'), # файл архива -- stdin ('f' с последующим '-'). # # Примечательно, что 'x' -- это команда, а 'p', 'v' и 'f' -- ключи # Во как! # Более элегантный вариант: # cd source-directory # tar cf - . | (cd ../target-directory; tar xzf -) # # cp -a /source/directory /dest имеет тот же эффект.
bunzip2 linux-2.4.3.tar.bz2 | tar xvf - # --разархивирование tar-файла-- | --затем файл передается утилите "tar"-- # Если у вас утилита "tar" не поддерживает работу с "bunzip2", # тогда придется выполнять работу в два этапа, с использованием конвейера. # Целью данного примера является разархивирование тарбола (tar.bz2) с исходными текстами ядра.
Обратите внимание, что в этом контексте "-" - не самостоятельный оператор Bash, а скорее опция, распознаваемая некоторыми утилитами UNIX (такими как tar, cat и т.п.), которые выводят результаты своей работы в stdout.
bash$ echo "whatever" | cat - whatever
В случае, когда ожидается имя файла, тогда "-" перенаправляет вывод на stdout (вспомните пример с tar cf) или принимает ввод с stdin.
bash$ file Usage: file [-bciknvzL] [-f namefile] [-m magicfiles] file...
Сама по себе команда file без параметров завершается с сообщением об ошибке.
Добавим символ "-" и получим более полезный результат. Это заставит командный интерпретатор ожидать ввода от пользователя.
bash$ file - abc standard input: ASCII text bash$ file - #!/bin/bash standard input: Bourne-Again shell script text executable
Теперь команда принимает ввод пользователя со stdin и анализирует его.
Используя передачу stdout по конвейеру другим командам, можно выполнять довольно эффектные трюки, например вставка строк в начало файла.
С помощью команды diff -- находить различия между одним файлом и частью другого:
grep Linux file1 | diff file2 -
И наконец пример использования служебного символа "-" с командой tar.
Пример 3-4. Резервное архивирование всех файлов, которые были изменены в течение последних суток
#!/bin/bash # Резервное архивирование (backup) всех файлов в текущем каталоге, # которые были изменены в течение последних 24 часов #+ в тарболл (tarball) (.tar.gz - файл). BACKUPFILE=backup archive=${1:-$BACKUPFILE} # На случай, если имя архива в командной строке не задано, #+ т.е. по-умолчанию имя архива -- "backup.tar.gz" tar cvf - `find . -mtime -1 -type f -print` > $archive.tar gzip $archive.tar echo "Каталог $PWD заархивирован в файл \"$archive.tar.gz\"." # Stephane Chazelas заметил, что вышеприведенный код будет "падать" #+ если будет найдено слишком много файлов #+ или если имена файлов будут содержать символы пробела. # Им предложен альтернативный код: # ------------------------------------------------------------------- # find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar" # используется версия GNU утилиты "find". # find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \; # более универсальный вариант, хотя и более медленный, # зато может использоваться в других версиях UNIX. # ------------------------------------------------------------------- exit 0
Могут возникнуть конфликтные ситуации между опреатором перенаправления "-" и именами файлов, начинающимися с символа "-". Поэтому сценарий должен проверять имена файлов и предаварять их префиксом пути, например, ./-FILENAME, $PWD/-FILENAME или $PATHNAME/-FILENAME.
Если значение переменной начинается с символа "-", то это тоже может быть причиной появления ошибок.
var="-n" echo $var # В данном случае команда приобретет вид "echo -n" и ничего не выведет.
- -
-
предыдущий рабочий каталог. [дефис] Команда cd - выполнит переход в предыдущий рабочий каталог, путь к которому хранится в переменной окружения $OLDPWD .

Не путайте оператор "-" (предыдущего рабочего каталога) с оператором "-" (переназначения). Еще раз напомню, что интерпретация символа "-" зависит от контекста, в котором он употребляется.
- -
-
Минус. Знак минус в арифметических операциях.
- =
-
В зависимости от контекста применения, символ "=" может выступать в качестве оператора сравнения.
- +
-
Плюс. Оператор сложения в арифметических операциях.
В зависимости от контекста применения, символ + может выступать как оператор регулярного выражения.
- +
-
Ключ (опция). Дополнительный флаг для ключей (опций) команд.
Отдельные внешние и встроенные команды используют символ "+" для разрешения некоторой опции, а символ "-" -- для запрещения.
- %
-
модуль. Модуль (остаток от деления) -- арифметическая операция.
В зависимости от контекста применения, символ % может выступать в качестве шаблона.
- ~
-
домашний каталог. [тильда] Соответствует содержимому внутренней переменной $HOME. ~bozo -- домашний каталог пользователя bozo, а команда ls ~bozo выведет содержимое его домашнего каталога. ~/ -- это домашний каталог текущего пользователя, а команда ls ~/ выведет содержимое домашнего каталога текущего пользователя.
bash$ echo ~bozo /home/bozo bash$ echo ~ /home/bozo bash$ echo ~/ /home/bozo/ bash$ echo ~: /home/bozo: bash$ echo ~nonexistent-user ~nonexistent-user
- ~+
-
текущий рабочий каталог. Соответствует содержимому внутренней переменной $PWD.
- ~-
-
предыдущий рабочий каталог. Соответствует содержимому внутренней переменной $OLDPWD.
- ^
-
начало-строки. В регулярных выражениях символ "^" задает начало строки текста.
- Управляющий символ
-
изменяет поведение терминала или управляет выводом текста. Управляющий символ набирается с клавиатуры как комбинация CONTROL + <клавиша>.
-
Ctl-C
Завершение выполнения процесса.
-
Ctl-D
Выход из командного интерпретатора (log out) (аналог команды exit).
"EOF" (признак конца файла). Этот символ может выступать в качестве завершающего при вводе с stdin.
-
Ctl-G
"BEL" (звуковой сигнал -- "звонок").
-
Ctl-H
Backspace -- удаление предыдущего символа.
#!/bin/bash # Вставка символа Ctl-H в строку. a="^H^H" # Два символа Ctl-H (backspace). echo "abcdef" # abcdef echo -n "abcdef$a " # abcd f # Пробел в конце ^ ^ двойной шаг назад. echo -n "abcdef$a" # abcdef # Пробела в конце нет backspace не работает (почему?). # Результаты могут получиться совсем не те, что вы ожидаете. echo; echo
-
Ctl-J
Возврат каретки.
-
Ctl-L
Перевод формата (очистка экрана (окна) терминала). Аналогична команде clear.
-
Ctl-M
Перевод строки.
-
Ctl-U
Стирание строки ввода.
-
Ctl-Z
Приостановка процесса.
-
- Пробельный символ
-
используется как разделитель команд или переменных. В качестве пробельного символа могут выступать -- собственно пробел (space), символ табуляции, символ перевода строки, символ возврата каретки или комбинация из вышеперечисленных символов. В некоторых случаях, таких как присваивание значений переменным, использование пробельных символов недопустимо.
Пустые строки никак не обрабатываются командным интерпретатором и могут свободно использоваться для визуального выделения отдельных блоков сценария.
$IFS -- переменная специального назначения. Содержит символы-разделители полей, используемые некоторыми командами. По-умолчанию -- пробельные символы.
Глава 4. Переменные и параметры. Введение.
Переменные -- это одна из основ любого языка программирования. Они учавствуют в арифметических операциях, в синтаксическом анализе строк и совершенно необходимы для абстрагирования каких либо величин с помощью символических имен. Физически переменные представляют собой ни что иное как участки памяти, в которые записана некоторая информация.
4.1. Подстановка переменных
Когда интерпретатор встречает в тексте сценария имя переменной, то он вместо него подставляет значение этой переменной. Поэтому ссылки на переменные называются подстановкой переменных.
- $
-
Необходимо всегда помнить о различиях между именем переменной и ее значением. Если variable1 -- это имя переменной, то $variable1 -- это ссылка на ее значение. "Чистые" имена переменных, без префикса $, могут использоваться только при объявлении переменный, при присваивании переменной некоторого значения, при удалении (сбросе), при экспорте и в особых случаях -- когда переменная представляет собой название сигнала (см. Пример 29-5). Присваивание может производится с помощью символа = (например: var1=27), инструкцией read и в заголовке цикла (for var2 in 1 2 3).
Заключение ссылки на переменную в двойные кавычки (" ") никак не сказывается на работе механизма подстановки. Этот случай называется "частичные кавычки", иногда можно встретить название "нестрогие кавычки". Одиночные кавычки (' ') заставляют интерпретатор воспринимать ссылку на переменную как простой набор символов, потому в одинарных кавычках операции подстановки не производятся. Этот случай называется "полные", или "строгие" кавычки. Дополнительную информацию вы найдете в Глава 5.
Примечательно, что написание $variable фактически является упрощенной формой написания ${variable}. Более строгая форма записи ${variable} может с успехом использоваться в тех случаях, когда применение упрощенной формы записи порождает сообщения о синтаксических ошибках (см. Section 9.3, ниже).
Пример 4-1. Присваивание значений переменным и подстановка значений переменных
#!/bin/bash # Присваивание значений переменным и подстановка значений переменных a=375 hello=$a #------------------------------------------------------------------------- # Использование пробельных символов # с обеих сторон символа "=" присваивания недопустимо. # Если записать "VARIABLE =value", #+ то интерпретатор попытается выполнить команду "VARIABLE" с параметром "=value". # Если записать "VARIABLE= value", #+ то интерпретатор попытается установить переменную окружения "VARIABLE" в "" #+ и выполнить команду "value". #------------------------------------------------------------------------- echo hello # Это не ссылка на переменную, выведет строку "hello". echo $hello echo ${hello} # Идентично предыдущей строке. echo "$hello" echo "${hello}" echo hello="A B C D" echo $hello # A B C D echo "$hello" # A B C D # Здесь вы сможете наблюдать различия в выводе echo $hello и echo "$hello". # Заключение ссылки на переменную в кавычки сохраняет пробельные символы. echo echo '$hello' # $hello # Внутри одинарных кавычек не производится подстановка значений переменных, #+ т.е. "$" интерпретируется как простой символ. # Обратите внимание на различия, существующие между этими типами кавычек. hello= # Запись пустого значения в переменную. echo "\$hello (пустое значение) = $hello" # Обратите внимание: запись пустого значения -- это не то же самое, #+ что сброс переменной, хотя конечный результат -- тот же (см. ниже). # -------------------------------------------------------------- # Допускается присваивание нескольких переменных в одной строке, #+ если они отделены пробельными символами. # Внимание! Это может снизить читабельность сценария и оказаться непереносимым. var1=variable1 var2=variable2 var3=variable3 echo echo "var1=$var1 var2=$var2 var3=$var3" # Могут возникнуть проблемы с устаревшими версиями "sh". # -------------------------------------------------------------- echo; echo numbers="один два три" other_numbers="1 2 3" # Если в значениях переменных встречаются пробелы, # то использование кавычек обязательно. echo "numbers = $numbers" echo "other_numbers = $other_numbers"