Как работает grep? - PullRequest
       38

Как работает grep?

15 голосов
/ 21 августа 2011

Я пытаюсь понять, как работает grep.

Когда я говорю grep "hello" *.*, получает ли grep 2 аргумента - (1) строку для поиска, то есть "привет" и (2) путь *.*?Или оболочка преобразует *.* в то, что grep может понять?

Где я могу получить исходный код grep?Я наткнулся на эту GNU grep ссылку.Один из файлов README говорит, что он отличается от unix grep.Как это так?

Я хочу посмотреть на исходную версию FreeBSD grep, а также ее версию для Linux (если они разные).

Ответы [ 4 ]

21 голосов
/ 21 августа 2011

Сила grep - это магия теории автоматов. GREP - это сокращение от Global Regular Expression Print. И он работает, создавая автомат (очень простая «виртуальная машина»: не полная по Тьюрингу); затем он «выполняет» автомат для входного потока.

Автомат - это граф или сеть узлов или состояний. Переход между состояниями определяется входным символом под пристальным вниманием. Специальные автоматы, такие как + и *, работают с переходами, которые возвращаются к себе. Классы символов, такие как [a-z], представлены веером: один начальный узел с ветвями для каждого символа на «спицах»; и обычно спицы имеют специальный «эпсилон-переход» в одно конечное состояние, поэтому его можно связать со следующим автоматом, который будет построен из регулярного выражения (строки поиска). Эпсилон-переходы позволяют изменять состояние без продвижения вперед в искомой строке.

Редактировать: Похоже, я не очень внимательно прочитал вопрос.

Когда вы вводите командную строку, она сначала предварительно обрабатывается оболочкой. Оболочка выполняет подстановку псевдонимов и подстановку имен файлов. После замены псевдонимов (они похожи на макросы) оболочка разделяет командную строку на список аргументов (разделенных пробелами). Этот список аргументов передается в функцию main() исполняемой командной программы в виде целого числа (часто называемого argc) и указателя на массив NULL-завершенных ((void *)0) массивов символов с нулевым символом в конце ('\0') .

Отдельные команды используют свои аргументы по своему усмотрению. Но большинство Unix-программ выводит дружественное справочное сообщение, если ему дан аргумент -h (поскольку он начинается со знака минус, он называется опцией). Программное обеспечение GNU также принимает опцию «long-form» --help.

Поскольку между различными версиями программ Unix существует множество различий, самый надежный способ узнать точный синтаксис, который требуется программе, - это запросить саму программу. Если это не говорит вам о том, что вам нужно (или это слишком загадочно, чтобы понять), вам следует проверить страницу руководства local (man grep). А для программного обеспечения GNU вы часто можете получить еще больше информации от info grep.

12 голосов
/ 21 августа 2011

Оболочка выполняет глобализацию (преобразование формы * в имена файлов). Вы можете увидеть это, если у вас есть простая программа на C:

#include <stdio.h>

int main(int argc, char **argv) {
    for(int i=1; i<argc; i++) {
        printf("%s\n", argv[i]);
    }
    return 0;
}

А затем запустите его так:

./print_args *

Вы увидите, что он печатает то, что соответствует, а не * в буквальном смысле. Если вы вызываете это так:

./print_args '*'

Вы увидите, что он получает буквально *.

6 голосов
/ 21 августа 2011

Оболочка расширяет '*.*' в список имен файлов и передает расширенный список имен файлов в программу, такую ​​как grep.Сама программа grep не выполняет расширение имен файлов.

Итак, в ответ на ваш вопрос: grep не получает 2 аргумента;оболочка преобразует '*.*' во что-то, что grep может понять.

GNU grep отличается от Unix grep поддержкой дополнительных опций, таких как -w и -B и -A.

Мне кажется, что FreeBSD использует версию GNU grep:

2 голосов
/ 21 августа 2011

То, как grep видит подстановочный аргумент, зависит от вашей оболочки.(Стандартный) В оболочке Bourne есть переключатель (-f) для отключения имени файла globbing ( см. Справочные страницы ).

Вы можете активировать этот переключатель в сценарии с помощью

set -f
...