Это старая версия (1.32) ОболочкаShell.

Содержание

Оболочка shell

На этой странице будут собраны и разбиты на разделы практические приёмы использования оболочки (shell). Так как сама по себе оболочка является всего лишь тонким «клеем» для объединения программ и файлов в новые инструменты (через конвеер и перенаправление ввода-вывода), в этот раздел будут помещены ссылки на другие вики-страницы, где описаны приёмы работы с прочими классическими утилитами Unix.

Конвеер для работы с файлами

 $ find /etc -maxdepth 1 -type f | sort | ( echo cat ; cat ) | paste -s -d ' ' | sh >/tmp/all

Я бы отдал предпочтение tr вместо paste, вот так:

 $ find /etc -maxdepth 1 -type f | sort | { echo cat; cat; } | tr '\n' ' ' | sh >/tmp/all

Здесь запуск подоболочки (subshell) заменён на блок (в фигурных скобках), так как преследовалась цель объединить последовательно вывод утилит echo и cat на стандартный вывод. Для этой цели подоболочку запускать расточительно.

Здесь есть ещё одна потенциальная проблема, она связана с тем, что в именаx файлов могут встречаться любые символы, кроме нулевого байта (NUL) и слеша (/). В имени файла может присутствовать символ новой строки (NL), в то же время find печатает список файлов, отделяя этим символом имена друг от друга. Если в имени файла содержится символ новой строки, тогда вывод find не отличим от двух файлов, следующих подряд.

Если используются утилиты GNU, то следует воспользоваться расширением, которое заменяет символ разделителя в списке файлов, выводимом find:

 $ find /etc -maxdepth 1 -type f -print0 | sort -z | xargs -0 cat >/tmp/all

Здесь find выводит имена файлов разделяя их не символом новой строки, а нулевым байтом (NUL). В этом случае все утилиты конвеера должны понимать это соглашение, например, GNU sort и GNU xargs умеют обрабатывать списки файлов с таким разделителем. -- СиткаревГригорий


Фильтр sed

 $ echo "abcabc" | sed 's/\(.*\)\(\1\)/\1#\2/'
 abc#abc

В данном примере в регулярном выражении используется backreference. Регулярное выражение состоит из двух групп выделенных круглыми скобками. Первой группе соотвествует любой набор символов .*, во второй группе используется backreference \1 (отсыл на первое выражение), при чем эта группа выделит выражение идентичное первому. В выводе мы адресуем группы как \1 и \2 и разделяем их символом #.

sed как язык программирования

На сегодняшний день sed в основном испозуется для замены или выделения выражений из входных данных. Но этот инструмент намного мощнее. sed это небольшой язык программирования со своей средой исполнения.

Далее текст можно рассматривать как небольшое введение по программированию на sed.

sed имеет два буфера, первый -- pattern буфер -- это входной буфер, он заполняется автоматически при обработке входных данных (или принудительно смотри команды n, N), второй -- hold буфер -- буфер хранения, данные в этот буфер могут попасть только по вызову специальной команды (смотри команды h, H). Пользователь может копировать, добавлять данные из одного буфера в другой, обменивать их содержимым друг с другом.

Команды могут объединяться в группы фигурными скобками:

 { action1; action2... }
а так же выполняться с условием, подобно ЯзыкAWK:
 condition { action }

где условие (condition) может быть регулярным выражением, номером строки или диапазоном строк.

Небольшой пример:

 $ sed -n 'H;${x;s/\n/ /g;p}' < /etc/passwd

H -- добавлять все входные строки из pattern буфер к данным в hold буфер, таким образом, мы накапливаем все входные строки в буфере хранения;

${ ... } -- $ означает последнюю строку, т.е все действия в фигурных скобках выполняться только при обработке последней строки;

x -- обменять содержимое hold буфера с содержимым pattern буфера, т.е все накопленные данные перемещаются из hold в ptatern буфер, а из pattern в hold буфер;

s/\n/ /g -- команда замены работает с pattern буфером, где теперь находятся все наши строки, заменяем символ переноса пробелом (g делаем это глобально, для всех \n);

p -- печатаем pattern буфер на экран. Все строки теперь объеднены в одну.

Слегка расширим предыдущий пример.

 $ sed -n '1h;1!H;${x;s/\n/ /g;p}' < /etc/passwd

1h -- первую строку копируем в hold буфер;

1!H -- все входные строки кроме первой добавляем в hold буфер, т.е дописываем к уже имеющимся в нем данным, ! знак инвертирования условия, в нашем случаи оно выполняется для всех строк кроме первой.

В остальном скрипт повторяет предыдущий.

Стоит отметить, что накопление значительных объемов данных может привести к переполнению внутренних буферов sed. Этого не должно произойти при использовании GNU sed.

Следующий пример удаляет все закоментированные и пустые строки:

 $ sed -e '/^ *#/d' -e '/^$/d' </etc/ssh/sshd_config

d -- удаляет pattern буфер, если условие верно, /^ *#/ строка с коментариями, /^$/ пустая строка, переходит к следующему циклу чтения, все последующие команды игнорируются.

Напечатать на экран строки с 5-ой по 8-ую:

 $ sed -n '5,8p' < /etc/passwd

Напечатать на экран лог ошибки сервера Apache за определенный период:

 $ sed -n '/^\[.*Feb 08/,/^\[.*Feb 10/p' < /var/log/apache2/error.log

/regexp1/,/regexp2/ -- условие задается двумя регулярными выражениями -- начальной и конечной датой.


Прокомментируйте, пожалуйста, что делают вышеперечисленные примеры вызова sed. -- СиткаревГригорий