Необходимо объединить строки для файла фиксированной ширины на основе длины

Я просмотрел glibc 2.24, который поставляется с Debian 9.

posix _spawnp (и posix _spawn )реализованы как пользовательский -код C режима, а не системный вызов. Он делает следующее:

  1. создает канал с флагом O_CLOEXEC.
  2. вызывает клон с флагом CLONE_VFORK. vfork ограничивает связь между дочерними и родительскими -здесь в игру вступает канал.
  3. Родитель закрывает конец канала для записи и пытается читать из конца для чтения.
  4. дочерний элемент закрывает конец канала для чтения и выполняет все действия с файлами.
  5. дочерний процесс вызывает execvp. В случае успеха труба должна быть закрыта . В случае неудачи дочерний элемент запишет в канал код ошибки.
  6. Чтение родителя возвращается. Если execvp в дочернем элементе завершился успешно, чтение должно завершиться ошибкой , поскольку конец записи канала должен был быть закрыт , а родитель устанавливает переменную ecв 0. Если чтение завершается успешно, ec— это код ошибки, отправленный ему потомком.
  7. posix _spawnp в родительском объекте возвращает ec.

Я выделил эти слова курсивом, потому что это ошибка.

Когда posix _spawnp выполняет все эти posix_spawn_file_actions_addcloseдействия, код glibc достаточно умен, чтобы дублировать конец записи канала, когда он видит действие файла, которое влияет на этот файловый дескриптор.

int p = args->pipe[1];
...
/* Dup the pipe fd onto an unoccupied one to avoid any file
   operation to clobber it.  */
if ((action->action.close_action.fd == p)
    || (action->action.open_action.fd == p)
    || (action->action.dup2_action.fd == p))
  {
    if ((ret = __dup (p)) < 0)
      goto fail;
    p = ret;
  }

Проблема в том, что дубликат не дублирует флаг O_CLOEXEC, поэтому fd передается процессу, который был запущен дочерним процессом, и не будет закрыт, пока этот процесс не завершится. Чтение в родительском элементе не вернется, пока это не произойдет.

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

Если вы застряли с этой версией glibc,вы ничего не можете сделать, кроме как не сообщать posix _spawnp закрыть конец записи канала (вероятно, logfd+2 в вашем примере кода ).

0
31.03.2021, 08:47
2 ответа

Для этого не нужно использовать два awk-скрипта, достаточно одного.

awk 'length($0) == 23 { print ; next };
     /^FEPS/ { line=$0; next };
     {
       line = line $0;
       if (length(line) == 23) print line;
       line="";
     }
    ' input

Вывод после сохранения исходного примера в файл с именемinput:

FEPS xxxx01 BUILDING 0
FEPS xxxx03 BUILDING 0
FEPS xxxx04 BUILDING 0
0
28.04.2021, 22:54
$ cat tst.awk
$1 == "FEPS" { prt(); rec="" }
{ rec = rec $0 }
END { prt() }

function prt() { if (length(rec) == 23) print rec }

$ awk -v n=23 -f tst.awk file
FEPS xxxx01 BUILDING 0
FEPS xxxx03 BUILDING 0
FEPS xxxx04 BUILDING 0
0
28.04.2021, 22:54

Теги

Похожие вопросы