Различия между зарезервированным словом и командой `time` для встроенной оболочки, функции, конвейера и списка команд?

1

В справочном руководстве Bash

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

  1. Не могли бы вы объяснить, почему цитата говорит это?

    Это из-за разницы между зарезервированным словом и командой, а не только в случае time? Например, как оболочка bash анализирует или интерпретирует их по-разному?

    Или это ограничено только случаем time?

  2. В следующих примерах

    почему внешняя сторона timeработает со встроенной оболочкой и конвейером, а в кавычках говорится, что «они не могут легко их определить»?

    Внешний timeна встроенной оболочке :

    $ /usr/bin/time echo hello
    hello
    0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 1676maxresident)k
    0inputs+0outputs (0major+78minor)pagefaults 0swaps
    

    Внешний timeпо трубопроводу :

    $ /usr/bin/time sleep 10 | sleep 5
    0.00user 0.00system 0:10.00elapsed 0%CPU (0avgtext+0avgdata 1776maxresident)k
    0inputs+0outputs (0major+79minor)pagefaults 0swaps
    
  3. В следующем примере, почему внешняя timeпо функции оболочки терпят неудачу? Что означает вывод ошибки?

    $ function mytest () { sleep 10; }
    
    $ /usr/bin/time mytest
    /usr/bin/time: cannot run mytest: No such file or directory
    Command exited with non-zero status 127
    0.00user 0.00system 0:00.03elapsed 0%CPU (0avgtext+0avgdata 1252maxresident)k
    32inputs+0outputs (0major+30minor)pagefaults 0swaps
    
  4. Кажется, что цитата относится не только к встроенным функциям оболочки, функциям оболочки и конвейерам, но и к группе команд :

    $ time { echo hello; sleep 3; echo tim; }
    hello
    tim
    
    real    0m3.002s
    user    0m0.000s
    sys 0m0.000s
    
    
    $ /usr/bin/time { echo hello; sleep 3; echo tim; }
    bash: syntax error near unexpected token `}'
    

    Почему оболочка говорит "bash: синтаксическая ошибка рядом с неожиданным токеном }" в случае команды /usr/bin/time?

Тим
источник

Ответы:

2

In bash, timeявляется зарезервированным словом , поэтому оболочка может проанализировать его по-своему и применить к нему правила.

Вот код, показывающий, как bashстрока разбора начинается с timeзарезервированного слова :

static int
time_command_acceptable ()
{
#if defined (COMMAND_TIMING)
  int i;

  if (posixly_correct && shell_compatibility_level > 41)
    {
      /* Quick check of the rest of the line to find the next token.  If it
     begins with a `-', Posix says to not return `time' as the token.
     This was interp 267. */
      i = shell_input_line_index;
      while (i < shell_input_line_len && (shell_input_line[i] == ' ' || shell_input_line[i] == '\t'))
        i++;
      if (shell_input_line[i] == '-')
    return 0;
    }

  switch (last_read_token)
    {
    case 0:
    case ';':
    case '\n':
    case AND_AND:
    case OR_OR:
    case '&':
    case WHILE:
    case DO:
    case UNTIL:
    case IF:
    case THEN:
    case ELIF:
    case ELSE:
    case '{':       /* } */
    case '(':       /* )( */
    case ')':       /* only valid in case statement */
    case BANG:      /* ! time pipeline */
    case TIME:      /* time time pipeline */
    case TIMEOPT:   /* time -p time pipeline */
    case TIMEIGN:   /* time -p -- ... */
      return 1;
    default:
      return 0;
    }
#else
  return 0;
#endif /* COMMAND_TIMING */
}

Видите ли, timeможет следовать большинство других bashзарезервированных слов.

В случае внешней команды применялось нормальное правило, {считалось вводом /usr/bin/time. }один неверный токен, и bashподнять ошибку.


В:

/usr/bin/time echo hello

external timeвызывал не встроенную оболочку, echoа внешнюю echoкоманду.

А straceпроверяет, что:

$ strace -fe execve /usr/bin/time echo 1
execve("/usr/bin/time", ["/usr/bin/time", "echo", "1"], [/* 64 vars */]) = 0
Process 25161 attached
....
[pid 25161] execve("/usr/bin/echo", ["echo", "1"], [/* 64 vars */]) = -1 ENOENT (No such file or directory)
[pid 25161] execve("/bin/echo", ["echo", "1"], [/* 64 vars */]) = 0
1
[pid 25161] +++ exited with 0 +++
....

Здесь внешний timeпоиск вашей PATHпеременной, чтобы найти исполняемый файл команды. Это также объясняет, что в случае использования функции у вас нет такого файла или каталога, потому что mytestв вашей команде нет названной команды PATH.

cuonglm
источник
«время - обратное слово». действительно?
@BinaryZebra: А также не стесняйтесь делать редактирование в следующий раз. Благодарю.
Cuonglm
Благодарю. Cuonglm. Я просто добавил некоторые детали к моим вопросам.
Тим
Благодарю. «В случае внешней команды было применено нормальное правило», что такое «нормальное правило»? Почему {считается ввод /usr/bin/time, а }один недействительный токен?
Тим
Я пытался найти его в спецификациях POSIX, но не могу найти.
Тим
1

В 2. вы можете видеть, что вывод неправильный, особенно для второго случая: /usr/bin/timeумножить на первую команду конвейера (10 с). Затем /usr/bin/time sleep 10вывод команды передается по конвейеру sleep 5. Это оболочка, которая ломает вашу командную строку таким образом: для нее, /usr/bin/timeкак и любая другая команда.

В 3. функции оболочки являются внутренними по отношению к процессу оболочки: /usr/bin/timeвызывается с аргументом mytest, ищет эту команду в пути и ничего не находит. /usr/bin/timeвызывается оболочкой, но не является ее частью.

Л. Леврел
источник