Использование sed для удаления строк из списка переменных

Использование sed для удаления строк из списка переменных

У меня есть скрипт, который использует sed в цикле для удаления строк, содержащих слова из списка:

for i in $list; do
  sed -i "/$i/d" file
done

$listсоздается из SQL-запроса:

list=$(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")

Проблема в том, что моя компания недавно внедрила более строгие правила аудита, которые включают все fchownили fchmodсистемные вызовы. Используя strace, я вижу, что каждый sed -iвключает один fchownи fchmodсистемный вызов.

При большом списке переменных iowaitзначение резко возрастает, и система фактически зависает, поскольку Auditd записывает в свой журнал нелепое количество строк.

Я пытаюсь выяснить, есть ли способ передать переменную list в sed одной строкой, чтобы файл открывался и закрывался только один раз.

Я уже спрашивал, любые изменения в правилах аудита бесполезны.

Спасибо.

решение1

Запустив его всего sedодин раз и используя один sedскрипт вместо того, чтобы вызывать миллиард встроенных команд одну за другой:

sedscript=$(mktemp)
for i in $list; do
  echo "/$i/d" >> "$sedscript"
done
sed -f "$sedscript" -i /path/to/file
rm -f "$sedscript"

решение2

Если вы можете аккуратно назначить слова в list, вы можете использовать расширение параметров bash, чтобы заменить каждый пробел на regex alternator |, а затем попросить grepсделать эту работу за вас:

list='auditd the to'
cp file temp &&  
grep -Ev "${list// /|}" temp > file && 
rm temp 

решение3

Если ваша оболочка поддерживает массивы, вы можете сделать что-то вроде

mapfile -t arr < <(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")

чтобы поместить вывод команды в массив оболочки, затем

printf '/%s/d\n' "${arr[@]}" | sed -i.bak -f - somefile

для применения последовательности удалений к somefile, на месте. Обычные предостережения применяются, если поля, возвращаемые вашей psqlкомандой, могут содержать символы, которые являются специальными для sed.

Это похоже на решение @DopeGhoti, за исключением того, что оно избегает временного файла скрипта (и должно обрабатывать пробелы в полях таблицы, если это необходимо).

решение4

Если это: psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC"дает вам список слов, разделенных пробелами, попробуйте это:

$ psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC" \
| awk -v FS=" " -v OFS="|" '{$1=$1; print "("$0")"}' \
| xargs -I {} sed -i -E '/{}/d' file

Связанный контент