355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Нейл Мэтью » Основы программирования в Linux » Текст книги (страница 8)
Основы программирования в Linux
  • Текст добавлен: 21 сентября 2016, 17:59

Текст книги "Основы программирования в Linux"


Автор книги: Нейл Мэтью


Соавторы: Ричард Стоунс
сообщить о нарушении

Текущая страница: 8 (всего у книги 67 страниц)

# find / -name test -print

/usr/bin/test

#

В зависимости от варианта установки системы на вашей машине вы можете найти и другие файлы, также названные test. Как вы, вероятно, догадываетесь, команда звучит так: "искать, начиная с каталога /, файл с именем test и затем вывести на экран имя файла". Легко, не правда ли? Безусловно.

Выполнение команды займет какое-то время, она будет искать на нашей машине и на сетевом диске машины с ОС Windows. Это происходит потому, что на компьютере с Linux смонтирована (с помощью пакета SAMBA) порция файловой системы машины с ОС Windows. Похоже, что подобный поиск будет вестись, даже если мы знаем, что искомый файл находится на машине под управлением ОС Linux.

В этом случае на помощь приходит первая опция. Если вы укажете опцию -mount, то сможете сообщить команде find о том, что смонтированные каталоги проверять не нужно.

# find / -mount -name test -print

/usr/bin/test

#

Мы нашли все тот же файл на нашей машине, но на сей раз гораздо быстрее и без поиска в смонтированных файловых системах.

Полная синтаксическая запись команды find выглядит следующим образом:

find [путь] [опции] [критерии] [действия]

Часть записи [путь] понятна и проста: вы можете указать абсолютный путь поиска, например, /bin, или относительный, например .. При необходимости можно задать несколько путей – например, find /var /home.

В табл. 2.10 перечислены основные опции команды.

Таблица 2.10


-depth Поиск в подкаталогах перед поиском в самом каталоге
-follow Следовать по символическим ссылкам
-maxdepths N При поиске проверять не болееN вложенных уровней каталога
-mount (или -xdev)Не искать в каталогах других файловых систем

Теперь о критериях. В команде find можно задать большое число критериев, и каждый из них возвращает либо true, либо false. В процессе работы команда find рассматривает по очереди каждый файл и применяет к нему все критерий в порядке их определения. Если очередной критерий возвращает значение false, команда find прекращает анализ текущего файла и переходит к следующему; если критерий возвращает значение true, команда применяет следующий критерий к текущему файлу или совершает заданное действие над ним. В табл. 2.11 перечислены самые распространенные критерии; полный список тестов, которые можно применять в команде find, вы найдете на страницах интерактивного справочного руководства.

Таблица 2.11


-atime N К файлу обращались последний раз N дней назад
-mtime N Файл последний раз изменялся N дней назад
-name шаблон Имя файла без указания пути соответствует заданному шаблону. Для гарантии того, что шаблон будет передан в команду find и не будет немедленно обработан командной оболочкой, его следует всегда заключать в кавычки
-newer другой файл Текущий файл, измененный позже, чем другой файл
-type С Файл типа C, где C может принимать определенные значения; наиболее широко используемые "d" для каталогов и "f" для обычных файлов. Остальные обозначения типов можно посмотреть на страницах интерактивного справочного руководства
-user имя пользователя Файл принадлежит пользователю с заданным именем

Вы также можете объединять критерии с помощью операторов. Как показано в табл. 2.12, у большинства из них две формы записи: короткая и более длинная форма.

Таблица 2.12


! -not Инвертирование критерия
-and Оба критерия должны быть истинны
-or Один из критериев должен быть истинным

Изменить порядок проверки критериев и выполнения операторов можно с помощью скобок. Поскольку в командной оболочке у них есть особое назначение, скобки также следует выделять с помощью обратного слэша. Кроме того, если вы применяете шаблон для имени файла, то следует использовать кавычки, чтобы оболочка не выполняла подстановку имени, а прямо передала шаблон команде find. Например, если вы хотите задать критерий "измененный позже, чем файл X, или с именем, начинающимся со знака подчеркивания", его можно записать следующим образом:

(-newer X -о -name «_*» )

Мы приведем пример сразу после описания "Как это работает". А сейчас выполните упражнение 2.16.

Упражнение 2.16 Применение команды find с критериями

Попытаемся найти в текущем каталоге файлы, измененные после модификации файла while2.

$ find . -newer while2 -print

.

./elif3

./words.txt

./words2.txt

./_trap

$

Все чудесно, за исключением того, что вы нашли ненужный вам текущий каталог. Вас интересуют только обычные файлы, поэтому добавьте дополнительный критерий -type f.

$ find . -newer while2 -type f -print

./elif3

./words.txt

./words2.txt

./_trap

$

Как это работает

Как это работает? Вы определили, что команда find должна искать в текущем каталоге (.) файлы, измененные позже, чем файл while2 (-newer while2), и, если этот критерий пройден, проверять с помощью следующего критерия (-type f), обычные ли это файлы. В заключение вы применили действие, с которым уже сталкивались, -print, просто для того чтобы подтвердить, что файлы были найдены.

Теперь найдем файлы с именами, начинающимися с символа подчеркивания или измененные позже, чем файл while2, но в любом случае обычные файлы. Этот пример покажет, как объединять критерии с помощью скобок.

$ find . ( -name «_*» -or -newer while2 ) -type f -print

./elif3

./words.txt

./words2.txt

./_break

./_if

./set

./_shift

./_trap

./_unset

./ until

$

Это не слишком трудный пример, не так ли? Вы должны экранировать скобки, чтобы они не обрабатывались командной оболочкой, и заключить в кавычки символ *, чтобы он также был передан непосредственно в команду find.

Теперь, когда вы можете правильно искать файлы, рассмотрим действия, которые можно совершить, когда найден файл, соответствующий вашей спецификации. И снова в табл. 2.13 перечислены только самые популярные действия; полный список можно найти на страницах интерактивного справочного руководства.

Таблица 2.13


-exec команда Выполняеткоманду. Наиболее широко используемое действие. После табл. 2.13 приведено объяснение способа передачи параметров в команду. Это действие следует завершать символьной парой ;
-ok команда Подобно действию exec, за исключением того, что перед обработкой файловкомандой выводится подсказка для получения подтверждения пользователя на обработку каждого файла. Это действие следует завершать символьной парой ;
-print Вывод на экран имени файла
-ls Применение команды ls -dils к текущему файлу

Команда в аргументах -exec и -ok принимает последующие параметры в строке как собственные, пока не встретится последовательность ; В действительности команда, в аргументах -exec и -ok выполняет встроенную команду, поэтому встроенная команда должна завершиться экранированной точкой с запятой, для того чтобы команда find могла определить, когда ей следует продолжить поиск в командной строке аргументов, предназначенных для нее самой. Магическая строка {} – параметр специального типа для команд -exec и -ok, который заменяется полным путем к текущему файлу.

Объяснение, возможно, не слишком легкое для понимания, поэтому рассмотрим пример, который поможет внести ясность. Взгляните на простой пример, использующий хорошую безопасную команду ls:

$ find . -newer while2 -type f -exec ls -l  {} ;

-rwxr-xr-x 1 rick rick  275 Feb 8 17:07 ./elif3

-rwxr-xr-x 1 rick rick  336 Feb 8 16:52 ./words.txt

-rwxr-xr-x 1 rick rick 1274 Feb 8 16:52 ./words2.txt

-rwxr-xr-x 1 rick rick  504 Feb 8 18:43 ./_trap

$

Как видите, команда find чрезвычайно полезна; она только требует небольшой практики для умелого ее применения. И такая практика, как и эксперименты с командой find, обязательно принесет дивиденды.

Команда grep

Вторая очень полезная команда, заслуживающая рассмотрения, – это команда grep. Необычное имя, означающее общий синтаксический анализатор регулярных выражений (general regular expression parser). Вы применяете команду find для поиска файлов в вашей системе, а команду grep для поиска строк в ваших файлах. Действительно, очень часто при использовании команды find команда grep передается после аргумента -exec.

Команда grep принимает опции, шаблон соответствия и файлы для поиска:

grep [опции] шаблон [файлы]

Если имена файлов не заданы, команда анализирует стандартный ввод.

Давайте начнем с изучения основных опций команды grep. И на этот раз в табл. 2.14 приведены только самые важные из них; полный список см. на страницах интерактивного справочного руководства.

Таблица 2.14


Вместо вывода на экран совпавших с шаблоном строк выводит их количество
-E Включает расширенные регулярные выражения
-h Ужимает обычное начало каждой строки вывода за счет удаления имени файла, в котором строка найдена
-i Не учитывает регистр букв
-l Перечисляет имена файлов со строками, совпадающими с шаблоном; не выводит сами найденные строки
-v Меняет шаблон соответствия для выбора вместо строк, соответствующих шаблону, несовпадающих с ним строк

Выполните упражнение 2.17.

Упражнение 2.17. Основной вариант использования команды grep

Посмотрим команду grep в действии на примерах простых шаблонов.

$ grep in words.txt

When shall we three meet again. In thunder, lightning, or in rain?

I come, Graymalkin!

$ grep -c in words.txt words2.txt

words.txt:2 words2.txt:14

$ grep -c -v in words.txt words2.txt

words.txt:9

words2.txt:16$

Как это работает

В первом примере нет опций; в нем просто ищется строка in в файле words.txt и выводятся на экран любые строки, соответствующие условию поиска. Имя файла не отображается, поскольку поиск велся в единственном файле.

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

В заключение применяется опция -v для инвертирования критерия поиска и подсчета строк, не совпадающих с шаблоном.

Регулярные выражения

Как вы убедились, основной вариант применения команды grep легко усвоить. Теперь пришло время рассмотреть основы построения регулярных выражений, которые позволят вам выполнять более сложный поиск. Как упоминалось ранее в этой главе, регулярные выражения применяются в системе Linux и многих языках программирования с открытым исходным кодом. Вы можете использовать их в редакторе vi и в скриптах на языке Perl, применяя одни и те же принципы, общие для регулярных выражений, где бы они ни появлялись.

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

Таблица 2.15


^ Привязка к началу строки
$ Привязка к концу строки
. Любой одиночный символ
[] В квадратных скобках содержится диапазон символов, с любым из них возможно совпадение, например, диапазон символов a-e или инвертированный диапазон, перед которым стоит символ ^

Если вы хотите использовать любые из перечисленных символов как «обычные», поставьте перед ними символ . Например, если нужно найти символ $, просто введите $.

Есть также несколько полезных специальных проверочных шаблонов, которые могут указываться в квадратных скобках (табл. 2.16).

Таблица 2.16


[:alnum:] Буквенно-цифровые символы
[:alpha:] Буквы
[:ascii:] Символы таблицы ASCII
[:blank:] Пробел или табуляция
[:cntrl:] Управляющие символы ASCII
[:digit:] Цифры
[:graph:] Неуправляющие и непробельные символы
[:lower:] Строчные буквы
[:print:] Печатные символы
[:punct:] Знаки пунктуации
[:space:] Пробельные символы, включая вертикальную табуляцию
[:upper:] Прописные буквы
[:xdigit:] Шестнадцатиричные цифры

Кроме того, если задана опция =E для расширенного соответствия, за регулярным выражением могут следовать и другие символы, управляющие выполнением проверки на соответствие шаблону (табл. 2.17). В команде grep перед этими символами необходимо вводить символ .

Таблица 2.17


? Совпадение не обязательно, но возможно не более одного раза
* Совпадения может не быть, оно может быть однократным или многократным
+ Совпадение должно быть однократным или многократным
{n} Совпадение должно быть n раз
{n, } Совпадение должно быть nраз и больше
{n, m} Совпадение должно быть от n до mраз включительно

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

1. Начнем с поиска строк, заканчивающихся буквой "е". Возможно, вы уже догадались, что нужно использовать специальный символ $:

$ grep e$ words2.txt

Art thou not, fatal vision, sensible

I see thee yet, in form as palpable

Nature seems dead, and wicked dreams abuse

$

Как видите, найдены строки, заканчивающиеся буквой "е".

2. Теперь найдите трехбуквенные слова, начинающиеся с символов "Th". В данном случае вам понадобится шаблон [[:space:]] для ограничения длины слова и . для единственного дополнительного символа.

$ grep Th.[[:space:]] words 2.txt

The handle toward my hand? Come, let me clutch thee.

The curtain'd sleep; witchcraft celebrates

Thy very stones prate of my whereabout,

$

3. В заключение примените расширенный режим поиска в команде grep для обнаружения слов из строчных букв длиной ровно 10 символов. Для этого задайте диапазон совпадающих символов от а до z и 10 повторяющихся совпадений.

$ grep -Е [a-z]{10} words2.txt

Proceeding from the heat-oppressed brain?

And such an instrument I was to use.

The curtain'd sleep; witchcraft celebrates

hy very stones prate of my whereabout,

$

Приведенные примеры лишь коснулись наиболее важных компонентов регулярных выражений. Как и для большинства составных частей ОС Linux, существует множество дополнительной документации помимо этой книги, которая поможет вам узнать еще больше подробностей, но лучший способ изучения регулярных выражений – экспериментировать с ними.

Выполнение команд

При написании сценариев вам часто требуется перехватить результат выполнения команды для использования его в сценарии командной оболочки; т.е. вы хотите выполнить команду и поместить ее вывод в переменную.

Сделать это можно с помощью синтаксической конструкции $(команда), показанной ранее в примере с командой set. Существует устаревший вариант подстановки команды `команда`, который все еще широко распространен.

Примечание

В более раннем варианте конструкции применяется обратный апостроф или обратная кавычка (`), а не обычный апостроф ('), который мы использовали раньше в командной оболочке для экранирования (защиты от подстановки переменных). В сценариях оболочки применяйте этот вариант, только если вы хотите добиться высокой степени переносимости сценариев.

Во всех современных сценариях следует применять конструкцию выполнения или подстановки команды $(команда), которая введена для того, чтобы избавиться от довольно сложных правил использования символов $' и внутри команды, заключенной в обратные апострофы. Если применяется обратный апостроф внутри конструкции `...` , его необходимо экранировать символом . Эти непонятные знаки часто заставляют программистов путаться, и иногда даже опытные специалисты в программировании средствами командной оболочки вынуждены ставить опыты для того, чтобы добиться правильного использования кавычек и апострофов в командах, заключенных в обратные апострофы.

Результат выполнения конструкции $(команда) – просто вывод команды. Имейте в виду, что это не статус возврата команды, а просто строковый вывод, показанный далее.

#!/bin/sh

echo The current directory is $PWD

echo The current users are $(who)

exit 0

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

Если вы хотите поместить результат в переменную, то можете просто присвоить его обычным образом:

whoisthere=$(who)

echo Swhoisthere

Возможность поместить результат выполнения команды в переменную сценария – очень мощное средство, поскольку оно облегчает использование существующих команд в сценариях и перехват результата их выполнения. Если когда-нибудь вам понадобится преобразовать набор параметров, представляющих собой вывод команды на стандартное устройство вывода, и передать их как аргументы в программу, возможно, вас порадует то, что команда xargs сможет это сделать за вас. Дополнительные подробности ищите на страницах интерактивного справочного руководства.

Иногда возникают проблемы, если команда, которую вы хотите выполнить, выводит несколько пробелов перед нужным вам текстом, или больше информации, чем вам нужно. В таких случаях можно воспользоваться командой set, как было показано ранее.

Подстановки в арифметических выражениях

Мы уже использовали команду expr, которая позволяет выполнять простые арифметические операции, но она делает это очень медленно, потому что для выполнения команды expr запускается новая командная оболочка.

Современная и лучшая альтернатива – синтаксическая конструкция $((...)). Поместив в эту конструкцию выражение, которое вы хотите вычислить, вы можете выполнить простые арифметические операции гораздо эффективнее.

#!/bin/sh

х=0

while [ «$х» -ne 10 ]; do

 echo $х

 х=$(($x+1))

done

exit 0

Примечание

Обратите внимание на тонкое отличие приведенной подстановки от команды х=$(...). Двойные скобки применяются для подстановки значений в арифметические выражения. Вариант с одиночными скобками, показанный ранее, используется для выполнения команд и перехвата их вывода.

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

Вы уже видели простейший вариант присваивания параметра и подстановки значения параметра:

foo=fredecho $foo

Проблема возникает, когда вы хотите вставить дополнительные символы в конец значения переменной. Предположим, что вы хотите написать короткий сценарий обработки файлов 1_tmp и 2_tmp. Вы могли бы написать следующие строки:

#!/bin/sh

for i in 1 2 do

 my_secret_process $i_tmp

done

Но в каждом проходе цикла вы получите следующее сообщение:

my_secret_process: too few arguments

В чем ошибка?

Проблема заключается в том, что командная оболочка попыталась подставить значение переменной $i_tmp, которая не существует. Оболочка не считает это ошибкой; она просто не делает никакой подстановки, поэтому в сценарий my_secret_process не передаются никакие параметры. Для обеспечения подстановки в переменную части ее значения $i необходимо i заключить в фигурные скобки следующим образом:

#!/bin/sh

for i in 1 2 do

 my_secret_process ${i}_tmp

done

В каждом проходе цикла вместо ${i} подставляется значение i и получаются реальные имена файлов. Вы подставляете значение параметра в строку.

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

Таблица 2.18


${парам:-значение по умолчанию} Если упарам нет значения, ему присваивается значение по умолчанию
${#парам} Задается длинапарам
${парам%строка} От конца значенияпарам отбрасывается наименьшая порция, совпадающая сострокой, и возвращается остальная часть значения
${парам%%строка} От конца значенияпарам отбрасывается наибольшая порция, совпадающая сострокой, и возвращается остальная часть значения
${парам#строка} От начала значенияпарам отбрасывается наименьшая порция, совпадающая сострокой, и возвращается остальная часть значения
${парам##строка} От начала значенияпарам отбрасывается наибольшая порция, совпадающая сострокой, и возвращается остальная часть значения

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

В приведенном далее сценарии показано применение шаблонов при подстановках значений параметров.

#!/bin/sh

unset foo

echo ${foo:-bar}

foo=fud

echo ${foo:-bar}

foo=/usr/bin/X11/startx

echo ${foo#*/}

echo ${foo##*/}

bar=/usr/local/etc/local/networks

echo ${bar%local*}

echo ${bar%%local*}

exit 0

У этого сценария следующий вывод:

bar

fud

usr/bin/X11/startx

startx

/usr/local/etc/usr

Как это работает

Первая подстановка ${foo:-bar} дает значение bar, поскольку у foo нет значения в момент выполнения команды. Переменная foo остается неизменной, т.е. она остается незаданной.

Примечание

Подстановка ${foo:=bar} установила бы значение переменной $foo. Этот строковый шаблон устанавливает, что переменная foo существует и не равна null. Если значение переменной не равно null, оператор возвращает ее значение, в противном случае вместо этого переменной foo присваивается значение bar.

Подстановка ${foo:?bar} выведет на экран foo: bar и аварийно завершит команду, если переменной foo не существует или ее значение не определено. И наконец, ${foo:+bar} вернет bar, если foo существует и не равна null. Какое разнообразие вариантов!

Шаблон {foo#*/} задает поиск и удаление только левого символа / (символ * соответствует любой строке, в том числе и пустой). Шаблон {foo##*/} задает поиск максимальной подстроки, совпадающей с ним, и, таким образом, удаляет самый правый символ / и все предшествующие ему символы.

Шаблон ${bar%local*} определяет просмотр символов в значении параметра, начиная от крайнего правого, до первого появления подстроки local, за которой следует любое количество символов, а в случае шаблона ${bar%%local*} ищется максимально возможное количество символов, начиная от крайнего правого символа значения и заканчивая крайним левым появлением подстроки local.

Поскольку в системах UNIX и Linux многое основано на идеи фильтров, результат какой-либо операции часто должен перенаправляться вручную. Допустим, вы хотите преобразовать файлы GIF в файлы JPEG с помощью программы cjpeg:

$ cjpeg image.gif > image.jpg

Порой вам может потребоваться выполнить такого рода операцию над большим числом файлов. Как автоматизировать подобное перенаправление? Это очень просто:

#!/bin/sh

for image in *.gif

do

 cjpeg $image > {image%%gif}jpg

done

Этот сценарий, giftojpeg, создает в текущем каталоге для каждого файла формата GIF файл формата JPEG.


    Ваша оценка произведения:

Популярные книги за неделю