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 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.