Comment ajouter un fichier à un autre sous Linux à partir du shell?

418

J'ai deux fichiers: file1et file2. Comment ajouter le contenu de file2àfile1 pour que le contenu de file1persiste dans le processus?

asir
la source

Réponses:

611

Utilisez la redirection intégrée bash (tldp) :

cat file2 >> file1
David
la source
2
Comment faites-vous que le fichier de destination ne vous appartient pas et que vous devez utiliser sudo?
Bijay Rungta
1
@BijayRungta: Il semble que vous ayez répondu à votre propre question. Vous préférez sudola catcommande (et entrez les informations d'identification si vous y êtes invité).
David
vous devez ... chmod 777 / etc / default / docker pour vous donner des autorisations d'écriture sur ce fichier - assurez-vous de restaurer les anciennes autorisations de fichier une fois cela fait
danday74
1
@Sigur: à moins qu'il n'y ait un moyen de diriger la sortie vers deux fichiers à la fois, cela impliquerait deux appels de la commande.
David
2
@Sigur ou jeter un oeil au teeprogramme: cat 1 | tee -a 2 3. Vous pouvez mettre autant de fichiers que vous le souhaitez après le commutateur --append(ou -apour faire court).
Stefan van den Akker
291

cat file2 >> file1

L' >>opérateur ajoute la sortie au fichier nommé ou crée le fichier nommé s'il n'existe pas.

cat file1 file2 > file3

Cela concatène deux fichiers ou plus en un seul. Vous pouvez avoir autant de fichiers source que nécessaire. Par exemple,

cat *.txt >> newfile.txt

Mise à jour 20130902
Dans les commentaires, eumiro suggère "n'essayez pas cat file1 file2 > file1." La raison pour laquelle cela peut ne pas aboutir au résultat attendu est que le fichier recevant la redirection est préparé avant l' >exécution de la commande à gauche de la . Dans ce cas, la première file1est tronquée à zéro et ouverte pour la sortie, puis la catcommande tente de concaténer le fichier désormais de longueur zéro plus le contenu de file2dans file1. Le résultat est que le contenu original de file1est perdu et à sa place se trouve une copie file2dont ce n'est probablement pas ce qui était attendu.

Mise à jour 20160919
Dans les commentaires, le tpartee suggère un lien vers des informations / sources de support. Pour une référence faisant autorité, je dirige le lecteur aimable vers la page de manuel sh à linuxcommand.org qui déclare:

Avant qu'une commande ne soit exécutée, ses entrées et sorties peuvent être redirigées à l'aide d'une notation spéciale interprétée par le shell.

Bien que cela indique au lecteur ce qu'il doit savoir, il est facile de le manquer si vous ne le recherchez pas et n'analyse pas la déclaration mot par mot. Le mot le plus important ici est «avant». La redirection est terminée (ou échoue) avant l'exécution de la commande.

Dans le cas de l'exemple du cat file1 file2 > file1shell, la redirection est effectuée en premier afin que les poignées d'E / S soient en place dans l'environnement dans lequel la commande sera exécutée avant son exécution.

Une version plus conviviale dans laquelle la priorité de redirection est longuement couverte peut être trouvée sur le site Web d'Ian Allen sous la forme d'un didacticiel Linux. Sa page Notes de redirection d'E / S a beaucoup à dire sur le sujet, y compris l'observation que la redirection fonctionne même sans commande. En passant ceci au shell:

$ >out

... crée un fichier vide nommé. Le shell configure d'abord la redirection d'E / S, puis recherche une commande, n'en trouve aucune et termine l'opération.

T.Rob
la source
17
@asir - n'essayez pas cat file1 file2 > file1- cela ne fonctionnera pas comme vous l'attendez probablement.
eumiro
5
En fait, c'est exactement ce dont il a besoin. Il dit «sans écraser le fichier actuel1». Les trois premiers ont complètement ignoré answerers cette partie de la question et a proposé une commande à l' aide >>qui va modifier le fichier file1. T.Rob a fait un travail bien supérieur pour expliquer sa réponse plutôt que de simplement courir pour soumettre quelque chose qui était, en fait, incorrect. Sur la base du texte de la question, je pense que cat file1 file2 > file3c'est la commande appropriée que @asir recherchait.
dm78
Merci pour les aimables paroles, David! Ce que @eumiro souligne ci-dessus mais n'entre pas dans les détails, c'est que l'opération à droite de >est exécutée en premier. Ainsi, l'exécution tenterait d' cat file1 file2 > file1abord de clobber file1puis de copier le fichier maintenant de longueur nulle sur lui-même. Cela a du sens lorsque vous pensez à l'ordre dans lequel les opérations pourraient et devraient se produire, mais il est suffisamment subtil pour surprendre de nombreuses personnes. Donc, si rien d'autre, eumiro et vous avez incité à une nouvelle amélioration de la réponse. Merci pour ça!
T.Rob
Aussi ne pas essayer cat fichier1 >> fichier1, cela entraînera le fichier à récursive réécrite, je fais erreur et cela seulement dans quelques secondes, 50 millions de lignes ont été mis en au fichier d' un peu auparavant quelques lignes douzaine.
Hendra Uzia
Aussi, juste pour le rendre un peu plus concis, si le "nouveau fichier" existe déjà, >> s'ajoute au fichier et > remplace le fichier.
rinogo
43

Remarque : si vous devez utiliser sudo , procédez comme suit :

sudo bash -c 'cat file2 >> file1'

La méthode habituelle de simplement ajouter sudoà la commande échouera, car l'escalade de privilèges ne se répercute pas sur la redirection de sortie.

jdunk
la source
6
Un autre idiome commun pour cela estcat file2 | sudo tee -a file1 > /dev/null
ianw
28

Essayez cette commande:

cat file2 >> file1
eumiro
la source
13

À titre de référence, l'utilisation de ddrescue fournit un moyen interruptible de réaliser la tâche si, par exemple, vous avez des fichiers volumineux et si vous avez besoin de faire une pause, puis de poursuivre ultérieurement:

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

C'est logfilele bit important. Vous pouvez interrompre le processus avec Ctrl-Cet le reprendre en spécifiant à nouveau la même commande exacte et ddrescue lira logfileet reprendra là où il s'était arrêté. L' -o Aindicateur indique à ddrescue de démarrer à partir de l'octet A dans le fichier de sortie ( file1). Il wc --bytes file1 | awk '{ print $1 }'suffit donc d' extraire la taille de file1en octets (vous pouvez simplement coller la sortie de lssi vous le souhaitez).

Comme indiqué par ngks dans les commentaires, l'inconvénient est que ddrescue ne sera probablement pas installé par défaut, vous devrez donc l'installer manuellement. L'autre complication est qu'il existe deux versions de ddrescue qui pourraient se trouver dans vos référentiels: consultez cette question askubuntu pour plus d'informations. La version que vous voulez est le GNU ddrescue, et sur les systèmes basés sur Debian est le paquet nommé gddrescue:

sudo apt install gddrescue

Pour d'autres distributions, vérifiez votre système de gestion de paquets pour la version GNU de ddrescue.

Zorawar
la source
1
Pour le bénéfice des nouveaux utilisateurs: ddrescue est un outil GNU, mais il peut ne pas exister sur votre Linux, Mac ou autre système de type Unix. ddrescue ne semble pas être requis par POSIX ou tout autre standard.
2

Une autre solution:

cat file1 | tee -a file2

tee a l'avantage que vous pouvez ajouter autant de fichiers que vous le souhaitez, par exemple:

cat file1 | tee -a file2 file3 file3

ajoutera le contenu de file1à file2, file3et file4.

Depuis la page de manuel:

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

catpeut être la solution facile, mais qui devient très lente lorsque nous concatérons de gros fichiers, find -printest de vous sauver, bien que vous deviez utiliser cat une fois.

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
la source
Le gain de temps que vous signalez pour votre commande combo find / cat est dû au fait que vous chronométrez uniquement la commande find qui imprime les noms des fichiers. Essayez de chronométrer l'intégralité de la commande comme ceci: time (find . -maxdepth 1 -type f -name 'bigFile*' -print0 | xargs -0 cat -- > outFile1)cela devrait produire des résultats similaires à votre commande cat only.
JoshMc
0

Vous pouvez également le faire sans cat, mais honnêtement, catc'est plus lisible:

>> file1 < file2

Le >>ajoute STDIN à file1et les <décharges file2à STDIN .

Alok Singh
la source
1
Ça ne marche pas.
user202729
@ user202729 Vous avez raison, cela ne fonctionne pas en bash. Cela fonctionne dans zsh.
Alok Singh