Script de shell simples para adicionar linhas do arquivo newdata
to datafile
. Deve ser fácil alterar newdata
para um aqui-doc. Isso realmente não é muito eficaz, pois chama grep
para cada (nova) linha de entrada:
target=datafile
while IFS= read -r line ; do
if ! grep -Fqxe "$line" "$target" ; then
printf "%s\n" "$line" >> "$target"
fi
done < newdata
Para cada linha, usamos grep
para ver se ela já existe no arquivo de destino, -F
para correspondência de sequência fixa (sem expressões regulares), -x
para correspondência de linha completa e -q
para suprimir saída de linhas combinadas. grep
retorna um código de erro falso se não encontrar uma linha correspondente, então acrescente ao arquivo de destino se o resultado negado for verdadeiro.
Mais efetivamente, em awk
. Isso depende de awk
poder manipular linhas arbitrárias como chaves para um array.
$ awk 'FNR == NR { lines[$0] = 1; next } ! ($0 in lines) {print}' datafile newdata
A primeira parte FNR == NR { lines[$0] = 1; next }
carrega todas as linhas do primeiro arquivo de entrada como chaves na matriz (associativa) lines
. A segunda parte ! ($0 in lines) {print}
é executada nas seguintes linhas de entrada e imprime a linha se não estiver na matriz, ou seja, nas "novas" linhas.
A saída resultante contém apenas as novas linhas, por isso precisa ser anexada ao arquivo original, por exemplo, com sponge
:
$ awk 'FNR == NR { lines[$0] = 1; next } ! ($0 in lines) {print}' datafile newdata | sponge -a datafile
Ou poderíamos ter awk
anexando as linhas à linha final, isso exige apenas passar o nome do arquivo para awk
:
$ target=datafile
$ awk -vtarget="$target" 'FNR == NR { lines[$0] = 1; next }
! ($0 in lines) {print >> target}' "$target" newdata
Para usar um aqui-doc com awk
, precisaremos adicionar -
(stdin) como um arquivo de origem explícito, além de definir o redirecionamento, portanto awk ... "$target" - <<EOF