
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
$list
wird 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 fchown
oder fchmod
Systemaufrufe einschließen. Wenn ich verwende strace
, sehe ich, dass jedes einen und einen Systemaufruf sed -i
einschließt .fchown
fchmod
Bei einer großen Listenvariable iowait
explodiert 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 sed
einmal ausführen und ein einziges sed
Skript 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 somefile
direkt auf anzuwenden. Die üblichen Einschränkungen gelten, wenn die von Ihrem psql
Befehl 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