Содержание
Оболочка 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 имеет два буфера, первый -- pattern буфер -- это входной буфер, он заполняется автоматически при обработке входных данных (или принудительно смотри команды n, N), второй -- hold буфер -- буфер хранения, данные в этот буфер могут попасть только по вызову специальной команды (смотри команды h, H). Пользователь может копировать, добавлять данные из одного буфера в другой, обменивать их содержимым друг с другом.
Команды могут объединяться в группы фигурными скобками:
{ action1; action2... }а так же выполняться с условием, подобно AWK:
condition { action }
Небольшой пример:
$ 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. -- СиткаревГригорий