html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Команда sponge: «губка» для стандартного ввода

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

Это достаточно детально описано в главе I/O Redirection в «Продвинутом руководстве по программированию на Bash» (Advanced Bash-Scripting Guide).

В частности, иногда бывает так, что вам нужно прочитать какой-то файл, как-то его обработать (например, выбрать оттуда только те строки, которые подходят под некое регулярное выражение), и затем записать результат в тот же самый файл. Допустим, ваш файл называется «messages.log», и вы хотите оставить в нём только те строки, которые начинаются со слова «Success», двоеточия и пробела (а все остальные строки убрать).

Можно предположить, что для этого подойдёт такая команда:

grep "^Success:\s" messages.log > messages.log

Но это предположение окажется неправильным — при выполнении этой строчки файл messages.log будет открыт на запись и очищен ещё до того, как grep начнёт его просматривать.

Впрочем, интересно то, что когда grep всё-таки будет запущен, он обнаружит, что вывод перенаправляется в тот же файл, который он пытается прочитать, и сразу же завершится со следующим сообщением:

grep: input file ‘messages.log’ is also the output

То же самое делает и GNU cat (попробуйте выполнить cat messages.log > messages.log):

cat: messages.log: input file is output file

Это делается путём сравнения устройства и inode для файла ввода с соответствующими значениями для файла, используемого для записи стандартного вывода. Посмотреть реализацию этого подхода можно в src/cat.c.

В BSD cat таких проверок, кстати, не предусмотрено, но в данном случае это не столь важно: файл так или иначе уже очищен, поэтому читать и записывать нечего, так что cat просто завершится.

Однако возьмём другой пример:

cat messages.log >> messages.log

В данном случае мы не очищаем messages.log, а дописываем вывод команды cat в конец файла. И если cat проверит, что эти два файла совпадают, и завершится, то файл останется в том же состоянии, а пользователь увидит ошибку. А вот если такой проверки нет, то cat войдёт в цикл и будет дополнять файл до тех пор, пока не закончится место или пока пользователь не завершит процесс.

А теперь давайте подумаем, как можно всё-таки записать вывод в тот же файл, который мы читаем. Очевидное решение — это использовать временный файл. То есть:

mv messages.log tmpmessages.log
grep "^Success:\s" tmpmessages.log > messages.log
rm tmpmessages.log

Нельзя сказать, что это очень удобно, но, по крайней мере, задача таким образом вполне себе решается.

Ещё один вариант — мы можем использовать sed.

sed -i -n -e '/^Success:\s/{p}' messages.log

Но это решение, конечно, не слишком универсально — ведь выбор строк, совпадающих по регулярному выражению, это лишь одна из многих задач, связанных с обработкой текста. К тому же, синтаксис в данном случае получается уже значительно сложнее.

Кстати, на самом деле sed тоже использует временный файл — в этом можно убедиться, посмотрев на вывод strace:

open("messages.log", O_RDONLY)                   = 3
…
open("./sedWiaEAG", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
…
read(3, "Success: 123\nError: 123\n", 4096)      = 24
write(4, "Success: 123\n", 13)                   = 13
read(3, "", 4096)                                = 0
…
close(3)                                         = 0
…
close(4)                                         = 0
…
rename("./sedWiaEAG", "messages.log")            = 0
close(1)                                         = 0
close(2)                                         = 0
exit_group(0)                                    = ?

Очевидно, что нужно иметь возможность как-то обойтись вообще без промежуточных файлов. И такая возможность есть — это программа sponge из moreutils.

sponge reads standard input and writes it out to the specified file. Unlike a shell redirect, sponge soaks up all its input before opening the output file. This allows constructing pipelines that read from and write to the same file.

sponge читает стандартный ввод и записывает его в указанный файл. В отличие от перенаправлений командной оболочки, sponge «впитыает» весь переданный ввод перед тем, как открыть файл, в который его требуется записать. Это позволяет использовать такие конвейеры, где чтение происходит из того же файла, в который осуществляется запись.

Итак, используя sponge, мы можем убрать из нашего примера перенаправление командной оболочки, и, вместо этого, передать имя файла, в который мы хотим записать результат, в качестве аргумента для команды sponge. Вывод команды grep мы передаём с помощью конвейера (pipe).

grep "^Success:\s" messages.log | sponge messages.log

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

Желаю всем отличной пятницы!
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

0

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • habrahabr.ru
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции