
У меня есть скрипт, который использует 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