Как поддерживать расширение подстановочных слов в моей собственной реализации оболочки?

#c #shell #wildcard #glob

#c #оболочка #подстановочный знак #глоб

Вопрос:

Я пишу свою собственную реализацию очень простой оболочки, но я хочу поддерживать расширение подстановочных слов. Я прочитал ответ здесь, в stackoverflow, в котором предлагается использовать glob(3) для расширения слова во время токенизации команды.

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

 ls -l *.c ../*.c
 

в оболочке:

 glob_t globbuf;

globbuf.gl_offs = 2;
glob("*.c", GLOB_DOOFFS, NULL, amp;globbuf);
glob("../*.c", GLOB_DOOFFS | GLOB_APPEND, NULL, amp;globbuf);
globbuf.gl_pathv[0] = "ls";
globbuf.gl_pathv[1] = "-l";
execvp("ls", amp;globbuf.gl_pathv[0]);
 

Есть идеи, как я могу сделать это динамичным и работать с командами, у которых нет подстановочных знаков, а также с теми, у которых есть только 1 или несколько подстановочных знаков?

Является ли glob(3) лучшим способом поддержки расширений подстановочных знаков для моей оболочки или есть лучший способ? Будут ли регулярные выражения лучшей альтернативой? Я пытаюсь учиться здесь, поэтому простите меня, если я что-то неправильно понял, поскольку я относительно новичок в этой области.

Вот мой токенизатор на случай, если это будет полезно:

 int build_args(char * cmd, char ** argv) {
char *token; 
token = strtok(cmd," ");
int i=0;
while(token!=NULL){
    argv[i]=token; 
    token = strtok(NULL," "); 
    i  ; 
}
    argv[i]=NULL; 
    return i; 
}
 

Ответ №1:

Мое экспертное мнение: glob(3) это не лучший способ, но это самый простой способ. Если вы собираетесь написать совершенно новую оболочку, то, возможно, у нее должны быть некоторые функции, которых нет в некоторых других оболочках, — в противном случае, почему бы не написать оболочку, которая могла бы содержать дополнительные подстановочные знаки, не поддерживаемые glob . Тогда вы не сможете использовать glob .

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

 % touch echo Hello world
% ls
echo  hello  world
% *
hello world
 

т. е. оператор глобуса, расширенный до echo hello world которого, был командой, которая была впоследствии запущена.

Но подстановочные знаки не действуют как подстановочные знаки, если они заключены, например, в кавычки.

Комментарии:

1. Спасибо за ваше руководство, но не могли бы вы рассказать мне, как я могу использовать glob(3) для сопоставления и расширения подстановочных знаков? Я выбрал его, потому что он самый простой, я не пытаюсь добавить больше функций, которых еще нет в других оболочках, я просто пытаюсь узнать, как они работают внутри, создавая их самостоятельно.

Ответ №2:

Прочитайте glob(7) — интересная спецификация. Прочитайте также системные вызовы (2). Поиграйте с strace(1) или ltrace(1) в каком-нибудь существующем процессе оболочки (чтобы понять, что на самом деле делает эта оболочка при ее запуске, и что системные вызовы оболочки делают при ее запуске).

Вы можете использовать glob(3) (но см. fnmatch(3) и nftw(3) …). Вы также можете использовать opendir(3) readdir(3) stat(2) closedir(3).

Наконец, GNU bash — это свободное программное обеспечение. Почему бы вам не скачать и не изучить его исходный код? Или загляните в код sash или в код zsh …. Оба имеют открытый исходный код!

Комментарии:

1. Как поможет strace?

2. Что важно в системных вызовах (2)?

3. Оболочки используют системные вызовы.

4. Все использует системные вызовы. Что конкретно актуально?

5. Я рекомендую изучить исходный код существующих оболочек