LINUX.ORG.RU

sed с выводом в консоль и записью в файл одновременно

 


0

1

есть файл 1.txt:

123:qqq
321:sss
234:www
456:sss

задача вывести в консоль все строки в которых есть ‘sss’ И перезаписать этот файл БЕЗ этих строк. Пока справился только со второй частью задачи:

cat 1.txt | sed -i '/[0-9]\+:sss/d' 1.txt

Но как вывести в консоль (НЕ в файл) эти удаленные строки? Задача выполнить минимум команд, чтобы сильно не нагружать сервер в случае большого файла и частого обращения.

cat 1.txt | sed -i '/[0-9]\+:sss/d' 1.txt

Здесь не нужен cat:

sed -i '/[0-9]\+:sss/d' 1.txt

sed с выводом в консоль и записью в файл одновременно

Чтобы было аккуратно, можно делать так:

sed '/[0-9]\+:sss/d' 1.txt | tee 2.txt && rm 1.txt && mv 2.txt 1.txt

---

UPD:

Но как вывести в консоль (НЕ в файл) эти удаленные строки?

Никак, sed их отбрасывает.

Можно написать комплексную функцию (@vodz писал построчный перебор файла, но я задолбаюсь искать по форуму), которая перебирает файл построчно. Нужно только переписать тело цикла, чтобы отбрасываемые строки писались в stdout/stderr, а остальные летели в файл.

mord0d ★★★★★
()
Последнее исправление: mord0d (всего исправлений: 2)
Ответ на: комментарий от mord0d

Чтобы было аккуратно, можно делать так:

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

Никак, sed их отбрасывает.

то есть нужно делать еще одну команду, например греп, для поиска?

salyamilili
() автор топика
Ответ на: комментарий от salyamilili

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

Открою страшный секрет: Опция -i в sed точно так же создаёт временный файл, а после прохода заменяет исходный файл временным. ☺ Никакой магии.

то есть нужно делать еще одну команду, например греп, для поиска?

Да, причём до прохода sed.

mord0d ★★★★★
()
Ответ на: комментарий от xaizek

Но перед этим их можно вывести. Мой вариант:

работает. спасибо! а что за конструкция такая sed $’ ’ - как ее интерпретировать по русски?

salyamilili
() автор топика
Ответ на: комментарий от salyamilili

Это строки, которые понимают последовательности вроде \n. Без перевода строки не удавалось завершить команду w, она считала ;d} частью имени файла.

xaizek ★★★★★
()

Ты описал свои фантазии на тему решения некой задачи, но не описал саму задачу.
Добро пожаловать в клуб!

zolden ★★★★★
()
Ответ на: комментарий от xaizek

Но перед этим их можно вывести. Мой вариант:

>sed -i $'/[0-9]\\+:sss/{w /dev/stdout\n;d}' 1.txt

данная конструкция работает корректно.

НО, когда ее запускаешь в php:

exec ("sed...", $out, $err);

то и ничего не удаляется и на выводе ничего нет ($err=1).

Когда же запускаешь без {w:

exec("sed -i '/[0-9]\\+:sss/d' 1.txt", $out, $err);

то sed срабатывает, единственное что в консоль и в $out ничего не прилетает

salyamilili
() автор топика
Ответ на: комментарий от salyamilili

Скорее всего проблемы с экранированием и $' (exec() наверное запускает sh, а не bash). Возможно, так будет работать:

exec ("sed -i '/[0-9]\\+:sss/{w /dev/stdout\n;d}' 1.txt", $out, $err);
xaizek ★★★★★
()
Ответ на: комментарий от mord0d

Открою страшный секрет: Опция -i в sed точно так же создаёт временный файл, а после прохода заменяет исходный файл временным. ☺ Никакой магии.

Так а какой страшный секрет кроется в копировании второй раз и удаления исходника?

salyamilili
() автор топика
Ответ на: комментарий от salyamilili

в копировании второй раз

Так в примере не используется inplace (опция -i). Поэтому аккуратно, лапками. ☺

mord0d ★★★★★
()
Ответ на: комментарий от xaizek

Можно разбить на два выражения -e 'до перевода строки' -e 'после перевода строки'

Не проверял работоспособность:

sed -i -e '/[0-9]\\+:sss/{w /dev/stdout' -e ';d}' 1.txt
anonymous
()
Ответ на: комментарий от anonymous

Я бы не догадался. Спасибо, буду знать. Работает, только \ лишний был:

sed -i -e '/[0-9]\+:sss/{w /dev/stdout' -e ';d}' 1.txt
xaizek ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.