Contanto que os números em seu exemplo não contenham o delimitador que sed
está usando (por padrão /
), o $p
em seu código será interpretado como uma expressão regular (com tudo o que isso significa ).
Seu código:
search_dir='dummy'
filename='numbers.txt'
for entry in "$search_dir"/*
do
while read p;
do
sed -i '' "/$p/d" $entry
done < $filename
done
Aqui, você deseja excluir todas as linhas nos arquivos em $search_dir
que contém qualquer um dos números em $filename
. Se isso funciona ou não, depende de como seu sed
trata -i ''
. Com algumas implementações de sed
, você teria que usar -i
sem um argumento.
Relacionado a sed -i
e portabilidade: Como posso conseguir portabilidade com sed -i (edição no local)?
É mais seguro gravar o resultado em um arquivo temporário e depois mover esse arquivo para o nome do arquivo original:
for entry in "$search_dir"/*
do
while read p;
do
sed "/$p/d" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done <"$filename"
done
Isso garante que ele funcionará independentemente de com que sed
implementação você está trabalhando. Em geral, é uma má idéia tentar fazer alterações locais nos arquivos durante o teste de um script, então você pode querer comentar que mv
antes de estar satisfeito com a maneira como o script funciona.
Isso ainda é um pouco inseguro como uma solução geral, já que você está realmente "usando dados como código" (os números são dados e você os usa como parte do seu script sed
). Isso significa que você pode facilmente causar um erro de sintaxe no script sed
apenas inserindo um /
em um dos números no arquivo de números.
Como a operação é tão simples, podemos usar grep
. Isso também elimina o loop while
interno:
for entry in "$search_dir"/*
do
grep -Fv -f "$filename" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done
Isso fará com que grep
leia seus padrões de $filename
e os aplique ao arquivo $entry
. O -v
significa que vamos descartar qualquer linha que contenha o padrão e -F
significa grep
não interpretará os números como expressões regulares, mas como sequências fixas. Com -f "$filename"
, obtemos grep
para ler as seqüências de caracteres de $filename
.
Se houver diretórios em $search_dir
, poderíamos ignorar estes:
for entry in "$search_dir"/*
do
[ ! -f "$entry" ] && continue
grep -Fv -f "$filename" "$entry" >"$entry.tmp" && mv "$entry.tmp" "$entry"
done
Outra maneira ainda mais segura de fazer sua operação é usar awk
. Já que com as soluções sed
e grep
acima, o número é correspondido em qualquer lugar na linha, é concebível que possamos excluir as linhas erradas. Com awk
, é fácil combinar apenas o segundo campo ~
-delimited nos dados:
for entry in "$search_dir"/*; do
[ ! -f "$entry" ] && continue
awk -F '~' 'NR==FNR { num[$0]; next } !($2 in num)' "$filename" "$entry" >"$entry.tmp" &&
mv "$entry.tmp" "$entry"
done
O programa awk
preenche primeiro um array / hash associativo com os números como chaves e, em seguida, imprime todas as linhas do arquivo $entry
cuja segunda coluna ~
-delimited não é uma chave nesse hash.