Verwenden von sed zum Löschen von Zeilen aus Listenvariablen

Verwenden von sed zum Löschen von Zeilen aus Listenvariablen

Ich habe ein Skript, das sed in einer Schleife verwendet, um Zeilen zu löschen, die Wörter aus einer Liste enthalten:

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

$listwird aus einer SQL-Abfrage erstellt:

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

Das Problem ist, dass meine Firma vor Kurzem strengere Auditd-Regeln eingeführt hat, die alle fchownoder fchmodSystemaufrufe einschließen. Wenn ich verwende strace, sehe ich, dass jedes einen und einen Systemaufruf sed -ieinschließt .fchownfchmod

Bei einer großen Listenvariable iowaitexplodiert die Zahl und das System gerät tatsächlich ins Stocken, weil auditd eine absurd hohe Anzahl von Zeilen in sein Protokoll schreibt.

Ich versuche herauszufinden, ob es eine Möglichkeit gibt, die Listenvariable in einer Zeile an sed zu übergeben, sodass die Datei nur einmal geöffnet und geschlossen wird.

Ich habe bereits gefragt, jegliche Änderung der Auditd-Regeln ist nicht möglich.

Danke.

Antwort1

Indem Sie es nur sedeinmal ausführen und ein einziges sedSkript verwenden, anstatt eine Zillion Inline-Befehle einzeln aufzurufen:

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

Antwort2

Wenn Sie die Wörter in sorgfältig zuweisen können list, können Sie die Bash-Parametererweiterung verwenden, um jedes Leerzeichen durch den Regex-Alternator zu ersetzen |und dann bitten grep, die Arbeit für Sie zu erledigen:

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

Antwort3

Wenn Ihre Shell Arrays unterstützt, können Sie Folgendes tun:

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

um die Ausgabe des Befehls in ein Shell-Array zu übertragen, dann

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

um die Löschsequenz somefiledirekt auf anzuwenden. Die üblichen Einschränkungen gelten, wenn die von Ihrem psqlBefehl zurückgegebenen Felder Zeichen enthalten könnten, die für speziell sind sed.

Dies ähnelt der Lösung von @DopeGhoti, mit dem Unterschied, dass die temporäre Skriptdatei vermieden wird (und Leerzeichen in Tabellenfeldern verarbeitet werden sollten, falls dies erforderlich ist).

Antwort4

Wenn Sie dadurch psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC"eine durch Leerzeichen getrennte Liste von Wörtern erhalten, versuchen Sie Folgendes:

$ 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

verwandte Informationen