Usando sed para excluir linhas da variável de lista

Usando sed para excluir linhas da variável de lista

Eu tenho um script que usa sed em um loop para excluir linhas contendo palavras de uma lista:

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

$listé criado a partir de uma consulta SQL:

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

O problema é que minha empresa implementou recentemente regras de auditoria mais rígidas que incluem todas fchownou fchmodsyscalls. Usando strace, vejo que cada sed -iinclui um fchowne fchmodsyscall.

Com uma variável de lista grande, iowaitdispara e o sistema fica paralisado porque o auditd está escrevendo uma quantidade ridícula de linhas em seu log.

Estou tentando descobrir se existe uma maneira de passar a variável de lista para sed em uma linha para que o arquivo seja aberto e fechado apenas uma vez.

Eu já perguntei, qualquer alteração nas regras do auditd é um fracasso.

Obrigado.

Responder1

Executando apenas seduma vez e usando um único sedscript em vez de invocar um zilhão de comandos em linha, um por um:

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

Responder2

Se você puder atribuir cuidadosamente as palavras em list, poderá usar a expansão do parâmetro bash para substituir cada espaço pelo alternador regex |e pedir greppara fazer o trabalho para você:

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

Responder3

Se o seu shell suportar matrizes, você poderia fazer algo como

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

para colocar a saída do comando em uma matriz de shell, então

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

para aplicar a sequência de exclusões a somefile, no lugar. As advertências usuais se aplicam se os campos retornados do seu psqlcomando contiverem caracteres especiais para sed.

Isso é semelhante à solução do @DopeGhoti, exceto que evita o arquivo de script temporário (e deve lidar com espaços em branco nos campos da tabela, caso seja necessário).

Responder4

Se isto: psql -d dbname -t -c "SELECT foo from table ORDER BY column DESC"fornecer uma lista de palavras delimitadas por espaços em branco, tente isto:

$ 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

informação relacionada