Usando sed para eliminar líneas de la variable de lista

Usando sed para eliminar líneas de la variable de lista

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

$listse 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 fchownlas fchmodllamadas al sistema. Usando strace, veo que cada sed -iincluye uno fchowny fchmodsyscall.

Con una variable de lista grande, iowaitse 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 seduna vez y usando un solo sedscript 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 grepque 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 psqlcomando 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

información relacionada