
Tengo un script que usa sed en un bucle para eliminar líneas que contienen palabras de una lista:
for i in $list; do
sed -i "/$i/d" file
done
$list
se crea a partir de una consulta SQL:
list=$(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")
El problema es que mi empresa implementó recientemente reglas auditadas más estrictas que incluyen todas fchown
las fchmod
llamadas al sistema. Usando strace
, veo que cada sed -i
incluye uno fchown
y fchmod
syscall.
Con una variable de lista grande, iowait
se dispara y el sistema realmente se atasca porque auditd está escribiendo una cantidad ridícula de líneas en su registro.
Estoy tratando de averiguar si hay una manera de pasar la variable de lista a sed en una línea para que el archivo solo se abra y cierre una vez.
Ya pregunté, cualquier cambio en las reglas auditadas no es viable.
Gracias.
Respuesta1
Ejecutándolo solo sed
una vez y usando un solo sed
script en lugar de invocar millones de comandos en línea uno por uno:
sedscript=$(mktemp)
for i in $list; do
echo "/$i/d" >> "$sedscript"
done
sed -f "$sedscript" -i /path/to/file
rm -f "$sedscript"
Respuesta2
Si puede asignar cuidadosamente las palabras en list
, puede usar la expansión de parámetros de bash para reemplazar cada espacio con el alternador de expresiones regulares |
y luego pedir grep
que haga el trabajo por usted:
list='auditd the to'
cp file temp &&
grep -Ev "${list// /|}" temp > file &&
rm temp
Respuesta3
Si su shell admite matrices, podría hacer algo como
mapfile -t arr < <(psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC")
para poner la salida del comando en una matriz de shell, luego
printf '/%s/d\n' "${arr[@]}" | sed -i.bak -f - somefile
aplicar la secuencia de eliminaciones a somefile
, en su lugar. Se aplican las advertencias habituales si los campos devueltos por su psql
comando pueden contener caracteres especiales para sed
.
Esto es similar a la solución de @DopeGhoti, excepto que evita el archivo de script temporal (y debe manejar espacios en blanco en los campos de la tabla, si fuera necesario).
Respuesta4
Si esto: psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC"
le proporciona una lista de palabras delimitada por espacios en blanco, intente esto:
$ 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