Откуда grep знает, что он записывает во входной файл?

если я попытаюсь перенаправить вывод grep в тот же файл, из которого он читает, например:

$ grep stuff file.txt > file.txt

Я получаю сообщение об ошибке grep: input file 'file.txt' is also the output. Как это grep определить это?

4 ответов


согласно исходному коду GNU grep,grep проверьте i-узлы входа и выхода:

  if (!out_quiet && list_files == 0 && 1 < max_count
      && S_ISREG (out_stat.st_mode) && out_stat.st_ino
      && SAME_INODE (st, out_stat))   /* <------------------ */
    {
      if (! suppress_errors)
        error (0, 0, _("input file %s is also the output"), quote (filename));
      errseen = 1;
      goto closeout;
    }

на out_stat заполняется путем вызова fstat против STDOUT_FILENO.

  if (fstat (STDOUT_FILENO, &tmp_stat) == 0 && S_ISREG (tmp_stat.st_mode))
    out_stat = tmp_stat;

глядя на исходный код - вы можете видеть, что он проверяет в этом случае (файл уже открыт для чтения grep) и сообщает об этом см. SAME_INODE проверьте ниже:

  /* If there is a regular file on stdout and the current file refers
     to the same i-node, we have to report the problem and skip it.
     Otherwise when matching lines from some other input reach the
     disk before we open this file, we can end up reading and matching
     those lines and appending them to the file from which we're reading.
     Then we'd have what appears to be an infinite loop that'd terminate
     only upon filling the output file system or reaching a quota.
     However, there is no risk of an infinite loop if grep is generating
     no output, i.e., with --silent, --quiet, -q.
     Similarly, with any of these:
       --max-count=N (-m) (for N >= 2)
       --files-with-matches (-l)
       --files-without-match (-L)
     there is no risk of trouble.
     For --max-count=1, grep stops after printing the first match,
     so there is no risk of malfunction.  But even --max-count=2, with
     input==output, while there is no risk of infloop, there is a race
     condition that could result in "alternate" output.  */
  if (!out_quiet && list_files == 0 && 1 < max_count
      && S_ISREG (out_stat.st_mode) && out_stat.st_ino
      && SAME_INODE (st, out_stat))
    {
      if (! suppress_errors)
        error (0, 0, _("input file %s is also the output"), quote (filename));
      errseen = true;
      goto closeout;
    }

вот как записать обратно в какой-то файл:

grep stuff file.txt > tmp && mv tmp file.txt

попробуйте pipline с cat или tac:

    cat file | grep 'searchpattern' > newfile

Это лучшая практика и сокращение для реализации