LINUX.ORG.RU

Удаление слов из списка в списке файлов

 ,


1

1

Приветствую всех монстров программирования! Сразу прошу отнестись с пониманием. По работе пишу иногда bash-скрипты, сильных знаний не имею.

Задача моя состоит в том, чтобы удалить в списке файлов строки, содержащие слова, которые тоже берутся из списка.

Было так:

#! /bin/bash

name=$1

#Получаем список файлов, где упоминается учетка пользователя
grep -liEs "$name" /etc/squid3/acls/* /var/lib/squidguard/db/* > "/tmp/path"
#Передаем список в переменную
path=`cat "/tmp/path"`

for i in $path
    do
        sed -i /$name/d $i
    done

#Показываем, в каких файлах пользователь был найден
echo -e "\033[1;32mUser was found in:\033[0m "$path""

#Переконфигурируем Сквид, чтобы больше не пускал этого юзера
squid3 -k reconfigure

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

sed -i /$name/d $i

А что, если у пользователя будет почти такая же учётка, но с дополнительными символами (напр. firebolt и firebolt2) ?

Если учёток, которые надо удалить, немного, то их все можно затолкать в одно выражение в sed, а если много, то можно завернуть всё, что есть в ещё один цикл, перебирающий имена.

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

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

firebolt
() автор топика

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

#!/bin/bash

sed 's,^,/,; s,$,/d,' | sed -if - /etc/squid3/acls/* /var/lib/squidguard/db/*
squid3 -k reconfigure

На стандартный ввод ожидается список пользователей.

Анонимус постом выше дело говорит. Исправь регулярные выражения так, чтобы они матчили только ник пользователя (я не знаю формат файлов сквида).

Jini ★★
()

Я тут обнаружил забавную команду sponge (находится в пакете moreultils), с её помощью можно результат grep направлять в исходный файл:

#!/bin/sh

user_list=$1 # File with user names

grep -lis -f "$user_list" /etc/squid3/acls/* /var/lib/squidguard/db/* | while read file_name
do
  grep -vis -f "$user_list" "$file_name" | sponge "$file_name"
done

Как-то так.

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

По-моему подход исходно не очень: зачем сначала выяснять, в каких файлах упоминается пользователь, а потом все совпадения из этих файлов удалять?

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

Не факт, что это быстрее (возможно, даже медленнее в силу того, что grep работает на несколько порядков аналогичных конструкций BASH, а только считанный файл - будет уже закеширован), но по крайней мере это будет программа на BASH, а не на «grep с параметрами» :)

Кстати, попробовал сделать так:

shopt -s extglob
f=$(</etc/fstab)
echo "${f//*([^$'\n'])defaults*([^$'\n'])/FAULT}"

Оно подвесило мне BASH и сожрало 100% одного ядра.

Наверное, это всё-таки бага, а не фича?

DRVTiny ★★★★★
()
Последнее исправление: DRVTiny (всего исправлений: 1)

Время переходит на какой-нибудь нормальный язык программирования: perl, python, ruby, etc.

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

Я не пишу на bash «из любви к искусству», если алгоритм на раскладывается на простую последовательность вызовов системных утилит с максимум одним циклом, то я лучше возьму perl.

А у ТС явно не тот случай, когда нужны хитрые оптимизации.

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

BASH - вполне себе сложный и богатый средствами язык, почему же его не использовать?

Т.е. я знаю целых две реальные причины, почему его не нужно использовать:

  • 1. в нативном виде это очень медленный язык
  • 2. в нём довольно много странных глюков, и они то появляются, то исчезают

Но 2 проявляется только если много и активно писать на BASH, обычный скриптописатель по мелочи этого даже не заметит. Ну а пункт (1) якобы вовсе неважен.

Зато у BASH есть огромное преимущество: в нём нет мерзооп. В этом плане он очень выгодно отличается от Python'а, который мразооп не просто предлагает, а буквально впихивает это Г насильно.

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

2. в нём довольно много странных глюков, и они то появляются, то исчезают

уже только поэтому не стоит писать на bash

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

отличается от Python'а, который мразооп не просто предлагает, а буквально впихивает это Г насильно.

Правильно, поэтому наш выбор - perl :)

cdslow ★★
()

printf %s\\n a b c d a b | grep -Fvf <(printf %s\\n a b) ( <(..)-bashism - как файл с соответсвующим содержимым)

anonymous
()
#!/bin/bash

while [ $1 ]; do
    echo -e "\033[1;32mUser $1 was found in:\033[0m "
    grep -liEs "$1" /etc/squid3/acls/* /var/lib/squidguard/db/* | tee /dev/stderr|xargs -r sed -i /$name/d
    shift
done
squid3 -k reconfigure

Запускать так

banusers.sh user1 user2 user3
#или так
banusers.sh $(<userlist.txt)

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

Мне кажется, так проще всего. Я удаляю имя из списков и заодно получаю список файлов, откуда имя было удалено. А второй момент - он важный.

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

У вас таки неприязнь к bash'у?)) Я думаю, для задач системного администратора bash'а вполне хватает. Даже для решения этой задачи уже предложено несколько вариантов. Надо углубиться в bash.

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

Класс! Спасибо за детали. Испробую ваш вариант в первую очередь.

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

Шутите?)) Да я просто забыл, что сам использовал. Сразу полез в --help, напомнил себе, что это. На параметр -v не обращал внимания раньше. Полезная вещь!

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

Шутите?))

Просто, когда человек сначала сам использует -liEs, а потом пишет, что -lis для него незнакомый параметр, возникает подозрение, что он использует копипасту, не пытаясь разобраться в том, что делает.

Хорошо, что это не так.

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

tee «раздваивает» выхлоп грепа, направляя его на stderr (для чтения человеком) и на вход xargs.

shift убирает первый параметр командной строки ($1), подставляя вместо него второй и так далее. Самый простой способ перебрать все параметры.

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

В итоге я использовал способ legolegs. Но вам спасибо за то, что обратили моё внимание на «grep -v» и на «sponge» - такую же нужную штуку, как "-i" у sed'а.

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

Два чая этому господину.

Использую похожую конструкцию у себя - shift + цикл на проверку $1 самый простой способ.

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

Только вокруг параметров, содержащих переменные надо кавычки использовать, а то неждан случиться может. while [ "$1" ]; do и так далее везде. На случай, если в $1 окажутся пробелы, опции и малыш Робин-брось-таблицу.

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