Como anexar um arquivo a outro no Linux a partir do shell?

418

Eu tenho dois arquivos: file1e file2. Como anexo o conteúdo de file2a file1para que o conteúdo file1persista no processo?

asir
fonte

Respostas:

611

Use o redirecionamento interno do bash (tldp) :

cat file2 >> file1
David
fonte
2
Como você faz com que o arquivo de destino não seja de sua propriedade e você precisa usar o sudo?
Bijay Rungta
1
@BijayRungta: Parece que você respondeu sua própria pergunta. Você precederia sudoo catcomando (e inserir credenciais, se solicitado).
David David
você precisa ... chmod 777 / etc / default / janela de encaixe para dar-se escrever permissões em que o arquivo - certifique-se de restaurar as antigas permissões de arquivo uma vez feito
danday74
1
@ Sigur: A menos que haja uma maneira de direcionar a saída para dois arquivos ao mesmo tempo, isso envolveria duas invocações do comando.
David
2
@Sigur ou ter um olhar para o teeprograma: cat 1 | tee -a 2 3. Você pode colocar quantos arquivos desejar após a troca --append(ou -aabreviação).
Stefan van den Akker
291

cat file2 >> file1

O >>operador anexa a saída ao arquivo nomeado ou cria o arquivo nomeado se ele não existir.

cat file1 file2 > file3

Isso concatena dois ou mais arquivos para um. Você pode ter quantos arquivos de origem for necessário. Por exemplo,

cat *.txt >> newfile.txt

Atualização 20130902
Nos comentários, eumiro sugere "não tente cat file1 file2 > file1". A razão pela qual isso pode não resultar no resultado esperado é que o arquivo que recebe o redirecionamento é preparado antes da >execução do comando à esquerda do . Nesse caso, primeiro file1é truncado para comprimento zero e aberto para saída, então o catcomando tenta concatenar o arquivo agora com tamanho zero mais o conteúdo de file2into file1. O resultado é que o conteúdo original file1é perdido e, em seu lugar, é uma cópia da file2qual provavelmente não é o esperado.

Atualização 20160919
Nos comentários, o tpartee sugere um link para informações / fontes de backup. Para uma referência autorizada, direciono o leitor gentil para a página de manual sh no linuxcommand.org, que afirma:

Antes de um comando ser executado, sua entrada e saída podem ser redirecionadas usando uma notação especial interpretada pelo shell.

Embora isso diga ao leitor o que ele precisa saber, é fácil perder se você não estiver procurando por ele e analisando a afirmação palavra por palavra. A palavra mais importante aqui é 'antes'. O redirecionamento é concluído (ou falha) antes da execução do comando.

No caso de exemplo do cat file1 file2 > file1shell, o redirecionamento é executado primeiro para que os identificadores de E / S estejam no local no ambiente em que o comando será executado antes de ser executado.

Uma versão mais amigável na qual a precedência de redirecionamento é abordada extensivamente pode ser encontrada no site de Ian Allen na forma de material didático do Linux. Sua página de notas de redirecionamento de E / S tem muito a dizer sobre o tópico, incluindo a observação de que o redirecionamento funciona mesmo sem um comando. Passando isso para o shell:

$ >out

... cria um arquivo vazio nomeado. O shell primeiro configura o redirecionamento de E / S, depois procura um comando, não encontra nenhum e conclui a operação.

T.Rob
fonte
17
@ asir - não tente cat file1 file2 > file1- isso não funcionará como você provavelmente está esperando.
eumiro
5
Na verdade, é exatamente disso que ele precisa. Ele diz "sem substituir o arquivo atual1". Os três primeiros respondentes têm ignorado completamente esta parte da pergunta e sugeriu um comando usando >>o que irá modificar o arquivo file1. T.Rob fez um trabalho muito superior ao explicar sua resposta, em vez de apenas correr para enviar algo que, de fato, estava incorreto. Com base no texto da pergunta, acredito que esse cat file1 file2 > file3é o comando apropriado que o @asir estava procurando.
Dm78 02/02
Obrigado pelas amáveis ​​palavras, David! O que @eumiro aponta acima, mas não entra em detalhes, é que a operação à direita da >é executada primeiro. Portanto, a execução cat file1 file2 > file1primeiro atrapalha e file1depois tenta copiar o arquivo agora com tamanho zero para si mesmo. Isso faz sentido quando você pensa na ordem em que as operações podem e devem ocorrer, mas é sutil o suficiente para pegar muitas pessoas de surpresa. Então, se nada mais, eumiro e você solicitaram uma melhoria adicional na resposta. Obrigado por isso!
T.Rob
Também não tente cat file1 >> file1, isso fará com que o arquivo seja reescrito recursivamente, eu o faço por engano e, em apenas alguns segundos, 50 milhões de linhas foram inseridas no arquivo a partir de apenas algumas dezenas de linhas.
Hendra Uzia
Além disso, apenas para torná-lo um pouco mais conciso, se o "novo arquivo" já existir, >> anexa ao arquivo e o > substitui .
rinogo 3/09/18
43

Nota : se você precisar usar o sudo , faça o seguinte:

sudo bash -c 'cat file2 >> file1'

O método usual de simplesmente anexar sudoao comando falhará, pois a escalação de privilégios não é transferida para o redirecionamento de saída.

jdunk
fonte
6
Outra expressão comum para isso écat file2 | sudo tee -a file1 > /dev/null
ianw
28

Tente este comando:

cat file2 >> file1
eumiro
fonte
13

Apenas para referência, o uso do ddrescue fornece uma maneira interruptível de realizar a tarefa se, por exemplo, você tiver arquivos grandes e a necessidade de pausar e continuar em algum momento posterior:

ddrescue -o $(wc --bytes file1 | awk '{ print $1 }') file2 file1 logfile

A parte logfileé importante. Você pode interromper Ctrl-Ce retomar o processo especificando exatamente o mesmo comando novamente e o ddrescue lerá logfilee continuará de onde parou. O -o Asinalizador diz ao ddrescue para iniciar a partir do byte A no arquivo de saída ( file1). Então, wc --bytes file1 | awk '{ print $1 }'apenas extrai o tamanho de file1bytes (você pode colar a saída dels se quiser).

Como apontado por ngks nos comentários, a desvantagem é que o ddrescue provavelmente não será instalado por padrão; portanto, você terá que instalá-lo manualmente. A outra complicação é que existem duas versões do ddrescue que podem estar em seus repositórios: veja esta pergunta do askubuntu para mais informações. A versão que você deseja é o GNU ddrescue, e nos sistemas baseados no Debian é o pacote chamado gddrescue:

sudo apt install gddrescue

Para outras distribuições, verifique seu sistema de gerenciamento de pacotes quanto à versão GNU do ddrescue.

Zorawar
fonte
1
Para o benefício de novos usuários: o ddrescue é uma ferramenta GNU, mas pode não existir no seu Linux, Mac ou outro sistema semelhante ao Unix. O ddrescue não parece ser exigido pelo POSIX ou por qualquer outro padrão.
2

Outra solução:

cat file1 | tee -a file2

tee tem o benefício de que você pode anexar a quantos arquivos desejar, por exemplo:

cat file1 | tee -a file2 file3 file3

vai anexar o conteúdo de file1a file2, file3efile4 .

Na página do manual:

-a, --append
       append to the given FILEs, do not overwrite
Stefan van den Akker
fonte
0

catpode ser a solução mais fácil, mas que fica muito lenta quando concateamos arquivos grandes, find -printé resgatá-lo, embora você precise usar o gato uma vez.

amey@xps ~/work/python/tmp $ ls -lhtr
total 969M
-rw-r--r-- 1 amey amey 485M May 24 23:54 bigFile2.txt
-rw-r--r-- 1 amey amey 485M May 24 23:55 bigFile1.txt

 amey@xps ~/work/python/tmp $ time cat bigFile1.txt bigFile2.txt >> out.txt

real    0m3.084s
user    0m0.012s
sys     0m2.308s


amey@xps ~/work/python/tmp $ time find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1

real    0m2.516s
user    0m0.028s
sys     0m2.204s
Amey Jadiye
fonte
A economia de tempo relatada para o comando find / cat combo é porque você está cronometrando apenas o comando find, que está imprimindo os nomes dos arquivos. Tente cronometrar o comando inteiro como este: time (find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1)e deve produzir resultados semelhantes ao seu comando somente gato.
21717 JoshMc
0

Você também pode fazer isso sem cat, embora honestamente catseja mais legível:

>> file1 < file2

A >>anexa STDIN para file1eo <despeja file2para STDIN .

Alok Singh
fonte
1
Isso não funciona.
User202729 de
@ user202729 Você está certo, não funciona no bash. Ele funciona no zsh.
Alok Singh