Como adicionar linhas / texto ao início de um arquivo

4

Temos o seguinte arquivo de exemplo:

tcpmux          1/tcp                           # TCP port service multiplexer
tcpmux          1/udp                           # TCP port service multiplexer
rje             5/tcp                           # Remote Job Entry
rje             5/udp                           # Remote Job Entry
echo            7/tcp
echo            7/udp
discard         9/tcp           sink null
discard         9/udp           sink null
systat          11/tcp          users
systat          11/udp          users
daytime         13/tcp
daytime         13/udp
qotd            17/tcp          quote
qotd            17/udp          quote
msp             18/tcp                          # Message send protocol (historic)
msp             18/udp                          # Message send protocol (historic)
chargen         19/tcp          ttytst source
chargen         19/udp          ttytst source

Como podemos adicionar as seguintes linhas ao início do arquivo?

# The latest IANA port assignments can be gotten from
#       http://www.iana.org/assignments/port-numbers
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
#
# Each line describes one service, and is of the form:
#
# service-name  port/protocol  [aliases ...]   [# comment]

Para que o arquivo se pareça com:

# The latest IANA port assignments can be gotten from
#       http://www.iana.org/assignments/port-numbers
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
#
# Each line describes one service, and is of the form:
#
# service-name  port/protocol  [aliases ...]   [# comment]
tcpmux          1/tcp                           # TCP port service multiplexer
tcpmux          1/udp                           # TCP port service multiplexer
rje             5/tcp                           # Remote Job Entry
rje             5/udp                           # Remote Job Entry
echo            7/tcp
echo            7/udp
discard         9/tcp           sink null
discard         9/udp           sink null
systat          11/tcp          users
systat          11/udp          users
daytime         13/tcp
daytime         13/udp
qotd            17/tcp          quote
qotd            17/udp          quote
msp             18/tcp                          # Message send protocol (historic)
msp             18/udp                          # Message send protocol (historic)
chargen         19/tcp          ttytst source
chargen         19/udp          ttytst source

A solução simples é copiar o arquivo original para file.bck , anexar as novas linhas ao arquivo e anexar file.bck ao arquivo.

Mas esta não é uma solução elegante.

    
por yael 17.01.2018 / 10:20

6 respostas

6

Solução relativamente elegante usando o editor de arquivos especificado POSIX ex - pelo menos elegante no sentido que isto irá lidar com qualquer conteúdo arbitrário em vez de depender de um formato específico (barras invertidas) ou uma ausência específica de formato.

printf '0r headerfile\nx\n' | ex file-with-contents

Isso abrirá file-with-contents em ex , lerá o conteúdo completo de headerfile no topo e salvará o buffer modificado novamente em file-with-contents .

Se o desempenho é uma preocupação SEVERA e os arquivos são enormes, isso pode não ser o caminho certo para você, mas (a) não há maneira geral de apresentar dados em um arquivo e (b ) Eu não espero que você esteja editando seu arquivo /etc/services freqüentemente .

Uma sintaxe ligeiramente mais limpa (a maneira que eu realmente codificaria isso):

printf '%s\n' '0r headerfile' x | ex file-with-contents

Um trecho de código mais complicado, mas convergente, que verificará se o início de services coincide EXACTLY com a totalidade de header , byte para byte e IF NOT preenche o conteúdo inteiro de header to services e salve as alterações, segue.

Isso é totalmente compatível com POSIX.

dd if=services bs=1 count="$(wc -c < header)" 2>/dev/null |
  cmp -s - header ||
    printf '%s\n' '0r header' x |
      ex services

Uma versão muito mais simples, usando a opção "-n" do GNU cmp :

cmp -sn "$(wc -c <header)" header services ||
  printf '%s\n' '0r header' x | ex services

É claro que nenhum deles é inteligente o suficiente para verificar as correspondências PARCIAIS, mas isso está muito além da capacidade de um simples liner, já que o trabalho de adivinhação estaria intrinsecamente envolvido.

    
por 17.01.2018 / 10:57
4

OK, decidi escrever uma resposta além de um comentário.

Você pode usar o comando i de sed como:

sed -i '1i \
# The latest IANA port assignments can be gotten from\
#       http://www.iana.org/assignments/port-numbers\
# The Well Known Ports are those from 0 through 1023.\
# The Registered Ports are those from 1024 through 49151\
# The Dynamic and/or Private Ports are those from 49152 through 65535\
#\
# Each line describes one service, and is of the form:\
#\
# service-name  port/protocol  [aliases ...]   [# comment]' file

O é para o% GNUsed. Para sed em Macs, você precisa usar sed -i '' -e ... , e para POSIX sed não existe uma maneira simples de fazer as coisas no lugar.

    
por 17.01.2018 / 10:38
4

Normalmente, você faz exatamente isso. Linhas de pré-carregamento para um arquivo são difíceis, pois os arquivos são apenas sequências de bytes, então você precisa mover os dados existentes para a frente para criar espaço para os novos dados, e não há um método direto para isso (pelo menos nenhum método padrão). Em teoria, pode-se imaginar um sistema de arquivos baseado em registros de tamanho variável, onde você poderia adicionar novos registros no início ou entre registros existentes, mas não é assim que funciona na prática.

Alguns sistemas de arquivos podem mover blocos de dados, mas são blocos de tamanho fixo e, portanto, não há muito uso para arquivos de texto, onde as linhas têm comprimentos variáveis.

Mesmo que você faça algo como sed -i ou perl -i , eles criarão um arquivo temporário nos bastidores apenas por esse motivo.

Então, seja elegante ou não, eu iria com:

cat prefix data > data.new && mv data.new data

Para algumas linhas, você pode usar (no GNU sed):

sed -i.bak -e '1i first prefix line' -e '1i second prefix line'  data

Mas gerar os comandos de inserção ou adicionar barras invertidas para cada linha a ser adicionada também não é elegante.

    
por 17.01.2018 / 10:33
0

Usado abaixo de um liner sed para alcançar o resultado. Como Testado funcionou bem

Deixe-me saber por quaisquer dúvidas

 sed '1s/.*/\n&/g' examplefile| sed '1r file2.txt'  | sed '1d'

examplefile === > é o inputfile

arquivo2.txt === > é o arquivo que contém o conteúdo que precisa ser anexado no início do examplefile

    
por 17.01.2018 / 12:59
0

Outra abordagem: Usando sponge do pacote moreutils que está disponível na maioria das distribuições Linux, você também pode fazer

$ cat - file.txt | sponge file.txt
# The latest IANA port assignments can be gotten from
#       http://www.iana.org/assignments/port-numbers
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
#
# Each line describes one service, and is of the form:
#
# service-name  port/protocol  [aliases ...]   [# comment]

Isso usa cat para combinar a reprodução da entrada padrão ( - ) seguida do arquivo original ( file.txt ) e canaliza a saída combinada para sponge , que grava o resultado no mesmo arquivo no lugar. Em seguida, cole seu cabeçalho no terminal e termine com Ctrl+D .

Como alternativa, se você já armazenou o cabeçalho em um arquivo separado, pode usar

cat header.txt file.txt | sponge file.txt

para alcançar o mesmo resultado.

    
por 17.01.2018 / 16:03
-2

Na falta de detalhes incomuns (como lidar com arquivos enormes), certamente, concatenar o cabeçalho e o arquivo em um temporário e depois renomear o temporário em seu lugar, é a solução mais elegante para mim.

cat header file.txt >file.tmp ; mv file.tmp file.txt
    
por 17.01.2018 / 14:41