Como anexar várias linhas a um arquivo, se essas linhas não existirem nesse arquivo?
Por exemplo, para adicionar vários aliases globais /etc/bash.bashrc
, uso um heredocument :
cat <<-"BASHRC" >> /etc/bash.bashrc
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
alias brc="nano /etc/bash.bashrc"
BASHRC
Fui criticado que esta operação não inclui uma maneira de verificar se as linhas já estão lá, e se reexecutar o heredocument por engano, poderia causar redundância, bem como conflito.
Shell script simples para adicionar linhas do arquivo
newdata
adatafile
. Deve ser simples mudarnewdata
para um arquivo here-doc. Isso realmente não é muito eficaz, pois exigegrep
cada (nova) linha de entrada:Para cada linha, usamos
grep
para ver se ela já existe no arquivo de destino,-F
para correspondência de string fixa (sem regexes),-x
para correspondência de linha completa e-q
para suprimir a saída de linhas correspondentes.grep
retorna um código de erro falso se não encontrar uma linha correspondente, portanto, anexe ao arquivo de destino se o resultado negado for verdadeiro.Mais efetivamente, em
awk
. Isso depende daawk
capacidade de manipular linhas arbitrárias como chaves para uma matriz.A primeira parte
FNR == NR { lines[$0] = 1; next }
carrega todas as linhas do primeiro arquivo de entrada como chaves no array (associativo)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, as "novas" linhas.A saída resultante contém apenas as novas linhas, portanto, precisa ser anexada ao arquivo original, por exemplo, com
sponge
:Ou poderíamos
awk
acrescentar as linhas à linha final, requer apenas passar o nome do arquivo paraawk
:Para usar um here-doc com
awk
, precisaremos adicionar-
(stdin) como um arquivo fonte explícito, além de configurar o redirecionamento, entãoawk ... "$target" - <<EOF
Esta solução é provavelmente um pouco diferente do que você tinha em mente, mas eu verificaria se um alias está realmente definido e apenas o adicionaria ao bashrc se não estivesse. Supondo que você esteja usando uma versão relativamente atual do Bash...
Crie isso
. ./scriptname
em vez de executá-lo como um script normal.Observação: se você tiver vários aliases de candidatos e tiver medo de convertê-los manualmente para o formato de matriz associativa, edite o arquivo com
vim
e execute este comando::%s/\valias *([^=]+)\=['"]?([^'"]+)['"]?$/aliases['\1']='\2'/
.OU coloque seus aliases candidatos (e nada mais) em um arquivo (por exemplo
/tmp/aliases.txt
) e substitua asaliases[..]='..'
linhas no script por isto:Claro, existem outras maneiras além de usar AAs, mas elas são limpas e fáceis de trabalhar... e estou totalmente dentro neste ponto. :)
Uma solução genérica para correspondências exatas (não otimizada para desempenho); o arquivo
input
contém as linhas a serem verificadas:Teste:
Saída do
awk
comando:Hmmmm. Que tal agora...
Coloque os aliases a serem adicionados no arquivo new . Então...
Classificamos de forma única os novos aliases e o conteúdo bashrc (colocamos em um arquivo temporário para evitar a condição de corrida quando anexamos a bashrc ) e os executamos em
comm
.comm
faz comparações linha por linha de arquivos classificados e mostra linhas únicas e comuns. Suprimimos as colunas 2 e 3 (-23
) para que o resultado seja simplesmente aquelas linhas que são exclusivas de new e as anexamos a bashrc . É isso.(Esta é uma abordagem totalmente diferente da minha outra resposta, concentrando-se em sua busca por mais "one-liner".)
A ordem das linhas anexadas é importante?
Se não, você pode tentar essa solução:
assumindo que você já salvou linhas para adicionar no arquivo
aliases
.comm
é o GNU coreutil (você pode ver a página de manual dele), que permite comparar dois arquivos classificados linha por linha.