Добавить в избранное | Сделать стартовой страницей

Большая Linux библиотека для пользователей OS Linux и ПО для нее
Есть что сказать? Нужен совет? Посети наш форум.


При поддержке
Продвижение сайта
Создание сайта
Администрирование сервера
настройка сервера
Администрирование сервера
настройка сервера
Администрирование сервера
аренда сервера


Кто командует парадом?

Автор : Виктор Хименко

Настало время вспомнить и о пользователе — ведь это для него, собственно, создаются файлы и запускаются процессы, — а также о том, что для управления системой ему необходим пользовательский интерфейс. В этой статье речь пойдет о традиционном для UNIX-систем интерфейсе командной строки и о языке наиболее популярного в Linux командного интерпретатора bash.

Вы, возможно, удивитесь: есть же графические оболочки, такие как GNOME или KDE; именно благодаря им наблюдается сейчас бурный рост популярности Linux! Разве с их появлением командная строка не превратилась в никому не нужный анахронизм? Вовсе нет. Она по-прежнему остается самым удобным средством комбинирования программ и автоматизации рутинных процедур.

Что касается графических оболочек, то они одновременно и слишком просты, и слишком сложны. Элементарные действия вроде запуска отдельных программ и основных операций с файлами выполняются там очень похоже на то, как это происходит в Windows, и пользователь, знакомый с Windows, легко освоит их без посторонней помощи. Организация же взаимодействия программ, наоборот, требует довольно высокой программистской квалификации: например, среда GNOME основана на модели CORBA, а манипулировать CORBA-объектами весьма непросто. Командный интерпретатор предоставляет в наше распоряжение некую «золотую середину» — возможности весьма широкие и при этом относительно легко осваиваемые.

Примеры и иллюстрации, как и в предыдущих статьях, приводятся на материале дистрибутива KSI-Linux Release 3.0 (Manticore).

Скрипты и интерпретаторы

Командный интерпретатор, как следует из его названия, интерпретирует команды, т. е. выполняет их непосредственно (без предварительной компиляции). Он обрабатывает команды, вводимые пользователем в командной строке, а также скрипты — заранее подготовленные последовательности команд, хранящиеся в текстовом виде.

Надо сказать, что скрипты играют в GNU/Linux (и UNIX вообще) куда более важную роль, чем командные файлы в Windows и DOS. Например, из более чем тысячи (!) программ в каталоге /usr/bin того компьютера, на котором пишутся эти строки, примерно четверть является скриптами того или иного вида, а уж количество вспомогательных скриптов, используемых разными программами для внутренних нужд и не предназначенных для исполнения «широкой публикой» (а потому хранящихся в других каталогах), вообще не поддается учету. На плечи скриптов ложится и большая часть «тяжелой работы» по запуску системы. А если требуется автоматизировать какие-либо действия, то самый простой способ — опять-таки написать несложный скрипт.

В любой «полноценной» (не сокращенной для помещения в тостер или мобильный телефон) версии GNU/Linux имеется не менее двух командных интерпретаторов плюс еще три-четыре языка скриптов, не используемых в командной строке (таких как perl, tcl, python или scheme), и это не считая «мини-языков» типа sed или awk. Почему бы не ограничиться одним интерпретатором и его командным языком? Главным образом потому, что люди не похожи друг на друга и у них разные предпочтения. И чтобы учесть интересы максимального числа пользователей, создатели дистрибутивов включают в них по несколько интерпретаторов, а администраторы обычно предоставляют пользователям своих систем право выбрать по собственному вкусу язык для работы в командной строке.

Из всех командных интерпретаторов для UNIX-систем два являются «классическими». Это B Shell (Bourne Shell), созданный Стефеном Бурном (Stephen R. Bourne) для седьмой версии UNIX, и C Shell, разработанный в Беркли Уильямом Джоем (William N. Joy). Язык C Shell, основанный на командном интерпретаторе шестой версии UNIX, содержал ряд расширений, помогающих в интерактивной работе и в написании скриптов: историю команд, псевдонимы (aliases), массивы и многое другое. Однако при всех своих несомненных преимуществах он имел один очень серьезный недостаток — был несовместим с B Shell.

Поэтому, когда FSF разработал интерпретатор bash (Bourne-Again SHell), сочетающий синтаксис B Shell с мощью C Shell, привлекательность C Shell значительно снизилась. И хотя многие бывшие пользователи BSD или коммерческих версий UNIX используют C Shell при работе в GNU/Linux, стандартом де-факто в этой ОС является bash. (Впрочем, для аварийных дискет bash, занимающий «целых» 420 Кбайт, великоват, и на них часто помещают более компактный интерпретатор, например A Shell, вмещающийся в 62 Кбайт.)

Именно bash интерпретирует основную массу скриптов из /usr/bin и подавляющее большинство вспомогательных скриптов. (Поскольку B Shell не может быть включен в GNU/Linux по лицензионным соображениям, скрипты, изначально рассчитанные на B Shell, также интерпретируются посредством bash.) Поэтому из всех командных интерпретаторов пользователю GNU/Linux в первую очередь необходимо освоить bash.

Подробно описывать bash в журнальной статье невозможно, да, впрочем, и не слишком нужно: в конце концов, он снабжен весьма подробной документацией, которая вызывается командой info bash. Здесь же мы остановимся на наиболее характерных и интересных его особенностях.

Команды и метасимволы

Конечно, bash может выполнять любые команды, имеющиеся в системе, но некоторые из них являются подпрограммами интерпретатора (внутренние команды), а некоторые другие, хотя и представляют собой самостоятельные программы, специально предназначены для использования в командных скриптах (внешние команды). Внутренних и внешних команд bash насчитывается более сотни; перечень наиболее, на мой взгляд, часто применяемых с краткими описаниями приводится во врезке на с. 154. (Оценка употребительности, разумеется, чисто субъективная: я, например, обычно получаю имя файла без пути с помощью конструкции ${filename//*/}, а кто-то, возможно, использует для этого специальную команду basename, хотя она внешняя и из-за этого работает несколько медленнее.)

Как же устроена сама команда? Ее базовая структура во всех языках скриптов одинакова и весьма проста: сначала записывается имя команды, за ним может следовать определенное число опций (ключей) и аргументов (параметров), отделяемых от имени и друг от друга пробелами. Регистр символов существенен в любом месте команды; имена большинства команд записываются строчными буквами. Специальные символы — ‘*’, ‘$’, ‘?’ ‘!’, ‘>’, ‘<’ и др. — используются в командах в качестве метасимволов, т. е. служат для управления работой самого интерпретатора; именно поэтому их избегают употреблять в именах команд, файлов, каталогов и т. д. При необходимости вывести на экран строку, содержащую спецсимволы, ее обычно заключают в кавычки (существуют и другие способы вывода спецсимволов, но этот — самый распространенный).

Стандартно каждая команда записывается на отдельной строке, но можно поместить в одной строке и несколько команд: они отделяются друг от друга точками с запятой, если нужно, чтобы очередная команда ждала завершения работы предыдущей, и амперсандами, если команды должны выполняться параллельно. Длинную команду, которой не хватает одной строки, можно перенести на следующую с помощью символа ‘’.

Радости интерактивной работы

Надо сказать, что для интерактивной работы bash предоставляет массу удобств (на которые вы уже, скорее всего, обращали внимание, если работали в GNU/Linux). Он поддерживает такие средства редактирования командной строки, как повтор символов, макросы, «карман» (буфер) и т. д., а также историю (т. е. возможность повторить ранее введенную команду) и настраиваемое автоматическое дополнение.

Так, чтобы запустить, скажем, программу mysql_ convert_table_format, достаточно набрать в командной строке mysql_co и нажать клавишу табуляции: bash, зная названия доступных команд, сам «допишет» имя. (Если в системе есть несколько команд, начинающихся с заданного префикса, он выдаст их перечень, а если их более 100, то предварительно уточнит, действительно ли нужен такой огромный список. Кстати, с помощью данного свойства bash легко выяснить число доступных команд: для этого достаточно нажать клавишу табуляции, находясь в начале строки.) А когда название команды введено (и после него поставлен пробел), интерпретатор позволяет тем же способом ввести имя файла.

Автозаполнение также можно вызвать, нажав клавишу (в ее роли обычно выступает ) одновременно с одним из специальных символов: ‘/’ вызывает дополнение имени файла, ‘!’ — команды, $ — переменной, ‘~’ — пользователя, @ — машины. А при нажатии последовательно клавиш +x и соответствующего специального символа выдается список возможных вариантов дополнения.

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

Шаблоны

Поскольку ряд идей B Shell был использован при создании командных интерпретаторов DOS и Windows NT (Windows 9X не имеет собственного интерпретатора), многие конструкции bash могут показаться вам знакомыми. Однако это сходство зачастую обманчиво и нередко вводит в заблуждение пользователя DOS/Windows. Хорошей иллюстрацией здесь могут послужить шаблоны.

Базовые правила задания шаблонов для имен файлов в bash довольно просты: ‘*’, как и в DOS, означает любое число любых символов, а ‘?’ — любой одиночный символ. Кроме того, можно перечислить символы в квадратных скобках (разрешается вставлять между ними пробелы); а символ ‘^’ или ‘!’ в начале такого списка будет указывать, что символы не должны встречаться в данной позиции.

Если интерпретатор DOS поручает обработку шаблонов конкретным командам, то bash выполняет ее самостоятельно и передает командам не шаблоны, а готовые списки подходящих файлов. В результате команды иногда ведут себя совсем не так, как ожидает пользователь DOS.

Рис. 1. Что же здесь произошло?

Посмотрите на рис. 1: исходя из опыта работы в DOS естественно было бы предположить, что каждый из файлов с именем вида ‘*.static’ будет скопирован в файл с таким же именем, но без расширения, а образовался файл с диким именем ‘*.’ (впрочем, это произошло только потому, что в каталоге имелся всего один файл, подходивший под шаблон; если бы их оказалось несколько, bash выдал бы сообщение об ошибке).

Как же тогда получить имена без расширений (точнее, с отсеченной частью после точки — в Linux нет расширений в понимании DOS)? Об этом вы узнаете в конце следующего раздела, посвященного переменным.

Переменные

Начнем с отличий между переменными bash и командного языка DOS. Их удобно продемонстрировать на примере.

Рассмотрим команду, которая «дописывает» в переменную окружения CLASSPATH путь к архиву JAVApackage (подобные команды часто вставляются в конфигурационные файлы инсталляторами различных программ). В DOS она имела бы приблизительно следующий вид:

set CLASSPATH=%CLASSPATH%;c:Program
 FilesBig Program
JAVApackage.jar

А в «версии для Linux» она может выглядеть так:

CLASSPATH=”$CLASSPATH${CLASSPATH:+:}
/opt/big-program/
JAVApackage.zip”
export CLASSPATH

или так:

export CLASSPATH=”$CLASSPATH${CLASSPATH:+:}/opt/
big-program/JAVApackage.zip”

Как видим, в DOS переменные ограничиваются с двух сторон символами ‘%’, а в bash маркируется только их начало — символом ‘$’: признаком конца служит первый символ, не разрешенный в именах переменных (разрешены буквы, цифры и символ подчеркивания). Кроме того, в bash нет команды, аналогичной SET: интерпретатор распознает присваивание значения переменной просто по наличию знака равенства.

Кстати, благодаря тому, что установка переменной окружения в bash не требует отдельной команды, ее можно сделать частью любой команды (рис. 2). Присвоенное таким образом значение действительно только для данной команды, а в среду bash изменения не вносятся.

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

Вернемся, однако, к нашему примеру. Несмотря на более короткую форму записи самих переменных и операции присваивания, «Linux-версия» оказалась длиннее. Во-первых, там, где командный язык DOS обходится одним-единственным знаком ‘;’, она содержит устрашающего вида конструкцию ${CLASSPATH:+:}, а во-вторых, в ней присутствует несколько загадочная для пользователя DOS команда export.

И то, и другое — следствие заботы о безопасности. Команда export делает переменную доступной другим командам. В командных файлах DOS переменные всегда внешние, и в подавляющем большинстве случаев это действительно нужно, поскольку переменные служат почти исключительно для обмена данными между программами. В bash же широко используются внутренние переменные — в качестве счетчиков, для хранения промежуточных результатов вычислений или имен файлов и т. д. Поэтому переменные, которые должны быть доступны за пределами данного скрипта, специальным образом отмечаются. Конечно, маловероятно, что имя внутренней переменной случайно совпадет с именем переменной окружения, в результате чего значение последней окажется испорченным и какая-то программа начнет работать неправильно, но, как говорил Козьма Прутков, «лучше перебдеть, чем недобдеть».

Конструкция ${CLASSPATH:+:} вставляет в строку двоеточие (которое в bash служит разделителем элементов CLASSPATH, а также PATH, играющей ту же роль, что и в DOS), но лишь при условии, что строка CLASSPATH не является пустой. Без этой меры предосторожности результатом выполнения команды могла бы оказаться переменная CLASSPATH вида :/opt/big-program /JAVApackage. zip, т. е. с пустым элементом в начале. Такой элемент обозначает текущий каталог, который в Linux, в отличие от DOS, необходимо включать в CLASSPATH (и в PATH) в явной форме. Причем в большинстве дистрибутивов это не делается — из тех же соображений «как бы чего не вышло».

Данное обстоятельство часто сбивает с толку начинающих пользователей Linux:

— Как же так: я ведь и атрибуты executable for all на файл MyGreatCommand поставил, и в первой строке #!/bin/sh написал, а мне все равно говорят: command not found!

— Конечно! Ведь ты же ее в PATH не поместил!

— Какой PATH? Она у меня в текущем каталоге!

— А у тебя разве текущий каталог входит в PATH?

— ???

Впрочем, путь к команде, находящейся в текущем каталоге, можно указать в форме ./MyGreatCommand, и этого будет достаточно, чтобы она запустилась.

Если в DOS с переменной можно сделать, грубо говоря, две вещи — присвоить ей значение и извлечь значение, присвоенное ранее, — то в bash вариантов намного больше: скажем, извлечь значение можно десятком разных способов, включая условное извлечение (с которым мы познакомились на примере конструкции ${CLASSPATH:+:}), извлечение подстроки и извлечение с использованием шаблона. В частности, конструкция ${X##шаблон} позволяет, извлекая строку, удалить из нее максимально возможную соответствующую шаблону подстроку, считая от начала, а ${X%шаблон} — минимально возможную, считая с конца. Так что отсечь «хвосты» упомянутым в предыдущем разделе именам файлов можно было бы, например, следующим образом:

for i in /bin/*.static
do j=${i##*/}
cp ”$i” ”${j%.static}”
done

Подробнее о разных вариантах извлечения переменных рассказывается во врезке на с. 156. А операторами for и do мы займемся во второй части статьи.

Системные переменные

Помимо переменных, используемых различными программами, в Linux, как и в DOS, есть специальные, или «системные» переменные, значение которых определено заранее, причем их намного больше. Так, DOS имеет переменную PROMPT, содержащую приглашение командной строки, а в bash ей соответствуют четыре переменных: PS1 — основное приглашение; PS2 — «вспомогательное» приглашение, выдаваемое, когда команда не уместилась на одной строке; PS3 — приглашение «команды» select (на самом деле это не команда, а специальная конструкция bash, призванная облегчить выбор из нескольких вариантов; впрочем, она используется довольно редко); PS4 — приглашение перед командами скрипта, выводимыми в режиме трассировки (заметим, что в bash, в отличие от командного интерпретатора DOS, скрипты по умолчанию не трассируются).

В документации bash описано множество переменных, устанавливаемых интерпретатором или влияющих на его поведение. Назовем для примера $RANDOM, дающую доступ к простому генератору псевдослучайных чисел, и $!, значение которой равно PID последней команды, запущенной из данного экземпляра интерпретатора на асинхронное выполнение. Нам уже встречались системные переменные ${CLASSPATH, $PATH, а также $LC_ALL, определяющая страну и язык. С другими, такими как $? — возвращаемое значение — или $* — список параметров, — мы познакомимся в дальнейшем.

Виктор Хименко,

Окончание в следующем номере.


* В. Хименко. «Файлы, файлы, файлы». «Мир ПК», № 2/2000, с. 64; № 3/2000, с. 50.
«Процессы, задачи, потоки и нити». «Мир ПК», № 5/2000, с. 42; № 6/2000, с. 54.


Команды bash

Перед тем как перечислять в алфавитном порядке наиболее употребительные команды bash, необходимо назвать три «справочных» команды, используемых почти исключительно при интерактивной работе, — help, info и man. Команда help выдает краткое описание любой встроенной команды bash, info предоставляет доступ к входящему в состав системы GNU развернутому справочнику, в котором bash, разумеется, подробно описан. Команда man позволяет обратиться к другому, более старому справочнику, где есть информация о ряде команд, не описанных в справочнике info (вообще говоря, команда info, не найдя сведений в собственном справочнике, ищет их и в справочнике man, однако кое-что можно получить только с помощью самой man). Естественно, команда help help позволяет получить справку по help, команда info info — по info, а man man — по man.

В приводимом ниже списке каждая команда снабжена пометкой, указывающей, как получить ее более подробное описание: (b) означает, что команда встроенная и, следовательно, информацию о ней предоставляет команда help, (i) соответствует команде info, (m) — команде man.

. (b) — синоним для команды source

: (b) — синоним для команды true

[ (b) — сокращение для команды test, но, в отличие от нее, требует закрывающей квадратной скобки

(( (b) — соотносится с командой let так же, как [ соотносится с test

[[ (b) — не вполне команда, а особое выражение, очень похожее на команду [ (test)

alias(b) — позволяет задавать псевдонимы для других команд

at(m) — ставит программу в очередь на выполнение в заданное время

atq(m) — в заданное время проверяет очередь программ на выполнение

atrm(m) — в заданное время удаляет программу из очереди на выполнение

awk(i) — язык для построчного сканирования и обработки файлов: простой, маленький и быстрый, но притом достаточно мощный

batch(m) — выполняет программу, когда система не слишком загружена

builtin(b) — позволяет вызвать встроенную команду bash, даже когда ее имя перекрыто именем функции или псевдонимом

bzip2(i) — более новая, чем gzip, программа сжатия файлов; работает медленнее, чем gzip, но обеспечивает лучший коэффициент сжатия

cat(i) — «склеивает» заданные файлы и выдает их на стандартный выход

cd(b) — изменяет текущий каталог

chgrp(i), chmod(i), chown(i) — изменяют соответственно группу, права доступа и владельца файла

command(b) — позволяет вызвать команду — встроенную или внешнюю, даже когда ее имя перекрыто именем функции или псевдонимом

cp(i) — копирует файлы и каталоги

cpio(i) — CoPy In/Out — системная программа создания архивов; не содержит встроенной поддержки сжатия файлов, но может использоваться совместно с gzip или bzip2

crontab(m) — позволяет модифицировать список регулярных заданий пользователя

cut(i) — выдает на стандартный выход выбранные части строк текстового файла

dd(i) — копирует файл блоками, выполняя одновременно некоторые дополнительные действия

du(i) — вычисляет объем, занятый на диске указанными файлами

declare(b) — позволяет задать имя и тип переменной (применяется не слишком часто, так как bash допускает использование необъявленных переменных)

df(i) — сообщает количество свободного и занятого места на диске

diff(i) — находит различия между двумя файлами

dirs(b) — выводит список запомненных подкаталогов

echo(b/i) — выводит на стандартный выход заданное сообщение

enable(b) — позволяет разрешить или запретить использование встроенных команд

eval(b) — выполняет аргументы так, как если бы они были введены в командной строке (ранее часто использовалась для обращения к переменной, имя которой содержится в другой переменной)

exec(b) — выполняет системный вызов exec, т. е. замещает процесс, где исполняется скрипт, другим, заданным в качестве параметра; часто используется в так называемых «скриптах-обертках» (wrapper scripts), настраивающих среду для выполнения программ

exit(b) — завершает работу командного интерпретатора (и, стало быть, скрипта)

export(b) — делает переменные данного скрипта доступными для других процессов, запущенных из командного интерпретатора

file(m) — определяет тип файла (по содержимому; эвристический анализ выполняется на основе гибкой настраиваемой базы данных)

find(m/i) — ищет файлы по множеству признаков, но не по содержимому

false(b/i) — возвращает код ненормального завершения

getopts(b) — довольно сложная команда, похожая на аналогичное средство системной библиотеки; позволяет создавать скрипты, понимающие сложные опции

grep(m) — ищет строки в файлах; может использоваться совместно с командами find и xargs для поиска файлов по содержимому

gzip(i) — стандартная для GNU программа сжатия файлов; способна распаковывать (но не создавать) файлы в формате compress — более старой UNIX-программы сжатия

install(i) — копирует файлы, одновременно позволяя устанавливать их атрибуты

kill(b/m) — позволяет послать процессу сигнал; по умолчанию посылается сигнал SIGTERM, останавливающий процесс; отсюда такое устрашающее название

less(m) — улучшенная по сравнению с more программа просмотра файлов

let(b) — вычисляет арифметическое выражение; выражение может содержать многие операторы языка Си, а также переменные

local(b) — создает локальную (внутри функции) переменную

logout(b) — завершает работу командного интерпретатора, являющегося основным (login shell)

ln(i) — создает ссылки на файлы (дополнительные жесткие или символические)

ls(i) — выводит список файлов (например, для заданного каталога)

md5sum(i) — подсчитывает для файлов 128-битовую контрольную сумму

mkdir(i) — создает подкаталог

mktemp(m) — создает временный файл (чтобы избежать «дыр» в безопасности, создавайте временные файлы только с помощью mktemp)

more(m) — постранично выводит файл на экран (служит для просмотра длинных файлов)

mv(i) — перемещает или переименовывает файлы (каталоги)

patch(i) — применяет diff-файл (см. diff) к исходному файлу

popd(b) — удаляет подкаталоги из списка запомненных подкаталогов

printf(b/i) — обеспечивает форматированную печать данных (имеет много общего с одноименной функцией стандартной библиотеки Си)

pushd(b) — добавляет подкаталог в список запомненных подкаталогов и перемещает подкаталоги внутри этого списка

pwd(b/i) — выводит путь к текущему каталогу

read(b) — считывает строку со стандартного ввода и присваивает прочитанные значения указанным переменным

readonly(b) — защищает переменную от случайных изменений

return(b) — выходит из функции и передает управление в вызвавшую программу

rm(i) — удаляет файлы (подкаталоги)

rmdir(i) — удаляет пустые подкаталоги

sed(i) — потоковый редактор (a Stream EDitor); дает возможность быстро производить с текстом простые операции (например, поиск с заменой)

select(b) — довольно сложная команда, позволяющая организовывать меню с выбором вариантов из списка (в действительности это даже не команда, а особая синтаксическая форма, родственная синтаксическим формам while и for)

set(b/i) — очень сложная команда:

  • без параметров выдает список всех определенных на данный момент переменных и функций
  • с параметрами вида +
  • все прочие параметры присваиваются последовательно переменным $1 $2 ... $N

(Команда help set не дает полного описания set; оно есть только в описании bash, получаемом командой info bash.)

shift(b) — сдвигает позиционные параметры ($1 становится равным $N, $2 — $N+1, $3 — $N+2 и т.д.)

sort(i) — сортирует файл

source(b) — читает и выполняет команды, содержащиеся в файле (часто используется для того, чтобы вынести определение переменных в отдельный файл конфигурации)

tar(i) — программа создания архивов (Tape ARchiver); не содержит встроенной поддержки сжатия файлов, но может использоваться совместно с gzip или bzip2

test(b/i) — вычисляет значение логического выражения; в основном проверяет атрибуты файлов (существует? пуст? исполняемый? подкаталог? и т. д.), однако может также сравнивать строки

tr(i) — заменяет одни символы на другие по заданной таблице подстановки

trap(b) — позволяет связать с сигналом особую обработку

true(b/i) — возвращает код успешного завершения

type(b) — возвращает «тип» слова, заданного в качестве аргумента (встроенная команда, псевдоним, функция и т. д.)

ulimit(b) — устанавливает или сообщает системные квоты для процесса (процессов)

umask(b) — назначение описано в статье «Файлы, файлы, файлы»

unalias(b) — удаляет имя из списка псевдонимов

uniq(i) — выводит уникальные (или, наоборот, повторяющиеся) строки в отсортированном файле

unset(b) — удаляет имя из списка переменных

wc(i) — подсчитывает число символов, слов и строк в файле

xargs(m) — получает параметры со стандартного входа и вызывает с этими параметрами заданную программу (по умолчанию echo)

Как уже говорилось, здесь перечислены далеко не все команды. В типичной системе GNU/Linux их значительно больше: есть, например, команды, выводящие восьмеричный и шестнадцатеричный дамп памяти (od и hexdump), печатающие начало и конец файла (head и tail), а ко многим упомянутым командам есть дополнительные (например, diff3 позволяет сравнить три файла, а bzcat — просмотреть файл, упакованный программой bzip2). Не попали в наш обзор и системные переменные, имеющие для bash особый смысл. Обо всем этом и о многом другом вы сможете узнать, набрав в командной строке слова info bash.

Вернуться


Извлечение значений переменных

[khim@localhost tmp]$ VAR1=1234567890
[khim@localhost tmp]$ VAR2=0987654321
[khim@localhost tmp]$ echo "$VAR1 $VAR2
 XXX${VAR1}XXX ZZZ${VAR2}ZZZ"
1234567890 0987654321 XXX1234567890XXX
 ZZZ0987654321ZZZ
[khim@localhost khim]$

$ X или ${X} — просто извлечь значение из переменной X (фигурные скобки необходимы тогда, когда после имени переменной следует буква или цифра).

[khim@localhost khim]$ ptr=VAR1
[khim@localhost khim]$ echo ${!ptr}
1234567890
[khim@localhost khim]$ ptr=VAR2
[khim@localhost khim]$ echo ${!ptr}
0987654321
[khim@localhost khim]$

${!X} — извлечь значение из переменной, имя которой хранится в переменной X. Вместе с массивами этого достаточно для создания и обработки весьма нетривиальных структур данных.

[khim@localhost tmp]$ echo "${#VAR1}"
10
[khim@localhost tmp]$ echo "${VAR1:${#VAR1}-3}"
890
[khim@localhost tmp]$

${#X} — получить длину строки X; эту операцию удобно комбинировать с извлечением подстроки.

[khim@localhost tmp]$ echo ${VAR4:?can not proceed
 without VAR4} ; echo Ok
bash: VAR4: can not proceed without VAR4
[khim@localhost tmp]$

${X:?выражение} — извлечь значение переменной, а если она не определена, остановить выполнение скрипта.

[khim@localhost tmp]$ echo
 "${VAR1:-ABCDEF} ${VAR3:-ABCDEF}"
1234567890 ABCDEF
[khim@localhost tmp]$ echo
 "${VAR1:-ABCDEF} ${VAR3:-FEDCBA}"
1234567890 FEDCBA
[khim@localhost tmp]$

${X:-выражение} — условное извлечение: если переменная определена (как VAR1), используется ее значение, иначе — заданное альтернативное выражение (как в случае с VAR3).

[khim@localhost tmp]$ echo
 "${VAR1:=ABCDEF} ${VAR3:=
ABCDEF}"
1234567890 ABCDEF [khim@localhost
 tmp]$ echo "${VAR1:
=ABCDEF} ${VAR3:=FEDCBA}"
1234567890 ABCDEF
[khim@localhost tmp]$

${X:=выражение} — то же, но альтернативное выражение становится на будущее значением переменной.

[khim@localhost tmp]$ echo "${VAR1:5} ${VAR2:5:3}"
67890 543
[khim@localhost tmp]$

${X:N1[:N2]} — извлечь из переменной X подстроку, начинающуюся с N1-го символа (и заканчивающуюся N2-м).

[khim@localhost tmp]$ echo "${VAR1#*[37]}
 ${VAR2#*[37]}
${VAR3#*[37]}"
4567890 654321 ABCDEF
[khim@localhost tmp]$ echo "${VAR1##*[37]}
 ${VAR2##*[37]}
${VAR3##*[37]}"
890 21 ABCDEF
[khim@localhost tmp]$ echo "${VAR1%[37]*}
 ${VAR2%[37]*}
${VAR3%[37]*}"
123456 0987654 ABCDEF
[khim@localhost tmp]$ echo "${VAR1%%[37]*}
 ${VAR2%%[37]*}
${VAR3%%[37]*}"
12 098 ABCDEF
[khim@localhost tmp]$

${X#шаблон}, ${X##шаблон}, S{X%шаблон}, S{X%%шаблон} — извлечь строку, удалив из нее часть, соответствующую шаблону. Шаблон строится по тем же правилам, что и для имен файлов, т. е. ‘*[37]’ — это любая последовательность символов, а затем либо ‘3’, либо ‘7’, а ‘[37]*’ — это ‘3’ или ‘7’, а затем любая последовательность символов. Операции ‘#’ и ‘%’ удаляют минимальную возможную подстроку, ‘##’ и ‘%%’ — максимальную, причем ‘#’ и ‘##’ — с начала строки, а ‘%’ и ‘%%’ — с конца.

[khim@localhost tmp]$ CDPATH=/bin
[khim@localhost tmp]$ CDPATH=/newpath$
{CDPATH:+:$CDPATH}
[khim@localhost tmp]$ echo ${CDPATH}
/newpath:/bin
[khim@localhost tmp]$ unset CDPATH
[khim@localhost tmp]$ CDPATH=/newpath$
{CDPATH:+:$CDPATH}
[khim@localhost tmp]$ echo ${CDPATH}
/newpath
[khim@localhost tmp]$

${X:+выражение} — операция, обратная условному извлечению. Может показаться мистической, но используется не так уж редко.

[khim@localhost tmp]$ echo "${VAR1/[123]/x}
 ${VAR2/
[123]/x} ${VAR3/[123]/x}"
x234567890 0987654x21 ABCDEF
[khim@localhost tmp]$ echo "${VAR1//[123]/x}
 ${VAR2//
[123]/x} ${VAR3//[123]/x}"
xxx4567890 0987654xxx ABCDEF
[khim@localhost tmp]$

${X/шаблон/выражение}, ${X//шаблон/выражение} — извлечь строку, заменив в ней часть, соответствующую шаблону, заданным выражением (поиск с заменой). Операция ‘/’ выполняет замену однократно, а ‘//’ повторяет ее до победного конца.


аэрография авто | бюро ремонта телефонов из магазина