LINUX.ORG.RU

Удалить строки с номерами, список которых в файле

 ,


1

1

Доброго! Подскажите пожалуйста. Есть файл с номерами строк, которые нужно удалить из другого файла. Номера рандомные. Просится sed, но что-то не выходит.

Нужно что-то вроде

sed -n '$(cat file1)d' file2

Спасибо.

В чем проблема считать номера из файла в цикле и скормить sed?
Только их нужно будет отсортировать и скармливать в обратном порядке, иначе беда будет.

Да, и чтоб тебе ответили по-конкретней, привел бы пример файла с номерами: там ведь по-разному их можно хранитьс

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

Cпасибо за подсказку про обратный порядок. А sed список строк не хавает как-то аргументом? Это первое. А второе - а как sedу передать переменной номер строки?

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

А не лучше ли написать коротенький скрипт на питоне (с использованием словарей)? Будет конечно не в одну сверхдлинную строчку, но зато будет читабельно.

zoroaster ()
Ответ на: комментарий от rusya_rr

Вот так не получается

Потому, что
1. В одинарных кавычках переменные не раскрываются
2. у тебя имя переменной сливается с командой d
3. sed у тебя выведет результат на экран, а нужно, чтобы записывал в тот же файл

$ echo "one
two
three
four
five
six" > file.txt

$ echo "2
3
6" > file_numbers.txt

$ cat file_numbers.txt | sort -r | uniq | while read N; do sed -i "${N}d" file.txt ; done                                                                    

$ cat file.txt
one
four
five

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

А не лучше ли написать коротенький скрипт на питоне (с использованием словарей)?

А еще лучше - C++. Будет читабельней. По крайней мере мне.

И вообще не понимаю, зачем этот bash. Сделали б сразу ассемблер командной оболочкой.

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 1)
[xxxxx]$ cat lines.txt
2
3
5
[xxxxx]$ cat data.txt
stroka 1
stroka 2
stroka 3
stroka 4
stroka 5
stroka 6
[xxxxx]$ perl -e 'open(my $lines, "<lines.txt"); my $numbers = {}; foreach(<$lines>) {chomp; $numbers->{$_} = 1;} open(my $data, "<data.txt"); $counter=1; foreach(<$data>) {print $_ if !$numbers->{$counter}; $counter++}'
stroka 1
stroka 4
stroka 6
[xxxxx]$

PHPFan ()

Полон тред велосипедостроителей, а ведь есть стандартный инструмент:

$ echo "one
two
three
four
five
six" > file.txt

$ echo "2
3
6" > sorted_line_numbers.txt

$ nl file.txt | join -v1 -o 1.2  - sorted_line_numbers.txt
one
four
five

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

Ты же понимаешь что твой способ открывает файл заново каждую итерацию?

У меня получилось шесть строчек:

from sys import argv
d = dict(map(lambda x: (int(x), ...), open(argv[1])))
f = open(argv[3], 'w')
for i, l in enumerate(open(argv[2])):
    if not i + 1 in d:
        f.write(l)

А еще лучше - C++. Будет читабельней. По крайней мере мне.

И вообще не понимаю, зачем этот bash. Сделали б сразу ассемблер командной оболочкой.

Сарказм?

zoroaster ()
Ответ на: комментарий от legolegs

nl file.txt

-ba хотя, а то совсем стыдно

-o 1.2

ага, давай от строк файла оставим только первое слово (да и в люмов случае пробелы сожмет)

Полон тред велосипедостроителей

иронично, да и сей велосипед крив изначально

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

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

$ cat file.txt 
one
two
three
four
five     spaces
six

eigth derp
nine woohoo hehehe
ten
eleven
$ cat unsorted_line_numbers.txt 
2
3
8
6
$ join -t $'\t' -o 1.2 -v1 --nocheck-order <(nl -ba -w1 file.txt) <(sort -n unsorted_line_numbers.txt) 
one
four
five     spaces

nine woohoo hehehe
ten
eleven

(upd) нет, не работает (если удалять 11 строку). Нужна опция join -n как у sort, а её нет. Я выбрал тупиковое направление.

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

Нужна опция join -n как у sort, а её нет. Я выбрал тупиковое направление.

ну да с join-ом не понятно как с полями быть, а с sort можно поизвращаться: есть -k<..>,<..> (но тут не знаю, обязана ли реализация номер из nums выхлопнуть раньше пронумерованной строки из file):

{ cat nums; cat file | nl -ba;} | sort -nuk1,1 | grep $'\t' | cut -f2-
anonymous ()
Ответ на: комментарий от anonymous

но тут не знаю, обязана ли реализация номер из nums выхлопнуть раньше пронумерованной строки из file

Это называется stable sort, опция -s.

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

Вах, красаучег! Спасибо, вот что я давно искал.

while read N; do sed -i "${N}d"
- не сог передать переменную sedу

rusya_rr ()
Ответ на: комментарий от legolegs

про join не думал, тоже прикольно. Нужно было быстро. Не дождался Сделал топором

tac filewithnumbers |sed "s/^/sed -i '/"|sed -s "s/$/d' filewithtext/" >>del_lines.sh;chmod +x ./del_lines.sh
Потому что не знаю, как передать список строк на удаление sedу. Не факт, что можно вообще.

rusya_rr ()

Я бы посоветовал на сях через mmap решить проблему. Элементарно бьешь входной файл на куски "от строки такой-то до такой-то", конец строки ищется влегкую при помощи strchr. Полученное пишешь в выходной файл или сразу на stdout.

Вот пример, меняющий местами два файла (как то написал, когда на ЛОРе была тема: как поменять местами два гигантских файла, если нет места под третий — временный). Его чуть подпилить, и будет то, что тебе надо.

Пхытонистов не слушай. У них мозга нет.

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

Это у тебя мозга нет. Речь шла о коротеньком скрипте который нужен прям вот сейчас (насколько я понимаю это нужно не в продакшен для сервиса). Лично моё решение короткое, понятное и оптимальное. Если взять и сравнить с аналогичным кодом на сях разница будет чувствоваться только на очень больших текстах, что не существенно при однократном использовании.

zoroaster ()
Ответ на: комментарий от anonymous

Я бы посоветовал на сях через mmap решить проблему.

На каких сях? :) Я нуб.

Пхытонистов не слушай. У них мозга нет.

Гы

rusya_rr ()
Ответ на: комментарий от anonymous

Да, файл небольшой. Отработало быстро. Понятно, что это мегаизврат.

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

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

А sed -i в цикле - это изврат. Однажды его придётся на sshfs через gprs использовать и его тормознутость аукнется.

anonymous ()
Ответ на: комментарий от zoroaster

Выйдет медленно и хуёво, а так ничего.

Если твой питоновский скрипт на big data натравить, выйдет тоже медленно и ... как ты там сказал.
Это я к чему: не придумывай проблемы.

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

Вариант с awk правда хорош, так как короче, и при этом использует стандартную тулзу - awk.


А по поводу

Однажды его придётся на sshfs через gprs использовать и его тормознутость аукнется.

Не придётся. Не придумывай проблем там, где их нет.

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

Таки позвольте поинтегесоваться на чём таки по вашему кашегно?

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

Факт в том что будет на порядок лучше чем сед в цикле.

Это не факт, а твоя фантазия. Фактом будут тесты, при том воспроизводимые более одно раза и не только у тебя.

Послушай: есть задача. Её нужно выполнить в кратчайшие сроки. Чтобы это сделать нужно 1) использовать те инструменты, которые знаешь 2) не придумывать дополнительные требования 3) иметь представление о цели и смысле происходящего.

Так вот: в ТЗ нет больших данных; нет работы по GPRS; нет кроссплатформенности или переиспользования в будущем. Всё это - фантазии, до тех пор, пока ТС не сказал обратное. В управлении проектами это называется gold plating, и за это очень сильно бьют по рукам.

Более того, особенно для одноразовых скриптов, плюс-минус десятки секунд в скорости работы кода в подавляющем большинстве случаев приемлемы, особенно если позволяют сократить десятки минут / часы разработки и дебаггинга.

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

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

В управлении проектами это называется gold plating, и за это очень сильно бьют по рукам.

Хотя в принципе ты прав, в данном конкретном случае решение на awk уже автоматически 0) простое и понятное 1) быстрое 2) не тормозит на медленном IO 3) кроссплатформенное 4) может быть переиспользовано 5) тривиально переделывается и становится пригодным для bigdata (файлы данных и строк любого размера).

Хороший программист именно так и должен писать.

legolegs ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.