Comment diviser un fichier et de le garder à la première ligne de chacune des pièces?
Donné: Un grand texte-fichier de données (par exemple, le format CSV) avec un "spécial" de la première ligne (par exemple, les noms de champ).
Voulais: Un équivalent de la coreutils split -l
de commande, mais avec la condition supplémentaire que la ligne d'en-tête du fichier d'origine, apparaissent au début de chacune des pièces ainsi produites.
Je devine que certains concoction de split
et head
fera l'affaire?
- Il semble raisonnable que quelqu'un doit ajouter que, comme une fonctionnalité intégrée de
split
, n'est-ce pas? - Probablement le facteur le plus important, contre ce devenu un haut-c'est que vous, en général, de reconstruire un fichier divisé par faire
cat a b c > reconstructed
. Étrangères lignes dans le fichier, la reconstruction approche ne permet pas de reproduire le fichier d'origine. - C'est ce que la prochaine (pas) "
unsplit --remove-header
" utilitaire est fait pour! Mais sérieusement,split
, si elle devait avoir un "répétez-d'en-tête" option, faut-il encore défaut à son comportement actuel. Vous ne utiliser l'en-tête des trucs si vous avez vraiment voulu. - Oui, je pense que
--keep-first N
serait sympa de faire une option poursplit
qui serait utile à la fois pour ligne et mode octet - Je pense que c'est une bonne idée, absolument très utile pour le fractionnement d'un fichier à des fins de distribution plutôt que de la reconstruction. C'est l'un de ceux "c'est simple, comment est-il pas encore là" dispose d'un utilitaire Unix, si vieux, que je suis sceptique quant aux "personnes à charge" n'ont pas refusé les propositions précédentes pour ce faire exactement la fonctionnalité pour une raison ou une autre.
- Sans aucun doute.
- Je pense que le raisonnement peut être tout simplement dû à la POSIX spec pour le split n'ayant pas cette option. Je peux seulement imaginer combien il est difficile d'ajouter des fonctionnalités aux normes de POSIX! opengroup.org/onlinepubs/009695399/utilities/split.html
- J'ai mis à jour ma réponse avec une fonction cool que GNU
split
fournit.
Vous devez vous connecter pour publier un commentaire.
C'est robhruska de script nettoyé un peu:
J'ai enlevé
wc
,cut
,ls
etecho
dans les lieux où ils sont inutiles. J'ai changé certains des noms de fichiers pour les rendre un peu plus utile. Je l'ai cassé sur plusieurs lignes seulement pour la rendre plus facile à lire.Si vous voulez obtenir la fantaisie, vous pouvez utiliser
mktemp
outempfile
pour créer un nom de fichier temporaire au lieu d'utiliser une codés en dur un.Modifier
De l'utilisation de GNU
split
il est possible de le faire:Éclaté pour des raisons de lisibilité:
Quand
--filter
est spécifié,split
exécute la commande (une fonction dans ce cas, qui doit être exporté) pour chaque fichier de sortie et définit la variableFILE
, dans la commande de l'environnement, du nom de fichier.Un filtre de script ou de la fonction pourrait faire toute manipulation, il voulait la sortie de contenu ou même le nom de fichier. Un exemple de ce dernier pourrait être pour la sortie d'un fixe nom de fichier dans une variable répertoire:
> "$FILE/data.dat"
par exemple.for $part in (split -l 1000 myfile); cat <(head -n1 myfile) $part > myfile.$part; done
split
, de nécessité, n'a pas de sortie surstdout
.split
pourrait la sortie de la noms des fichiers sur la sortie standard, mais (aussi longtemps que nous sommes en train de discutersplit
doit à voir 🙂Vous pouvez utiliser la nouvelle --la fonctionnalité filtre dans GNU coreutils split >= 8.13 (2011):
tail -n +2 FILE.in | split -d --lines 50 - --filter='bash -c "{ head -n1 ${FILE%.*}; cat; } > $FILE"' FILE.in.x
Vous pouvez utiliser [mg]awk:
100 est le nombre de lignes de chaque tranche.
Il ne nécessite pas de fichiers temporaires et peut être mis sur une seule ligne.
Je suis un novice quand il s'agit de Bash-fu, mais j'ai réussi à concocter ce deux-commande de la monstruosité. Je suis sûr qu'il y a de plus élégant des solutions.
C'est en supposant que votre fichier d'entrée est
file.txt
, vous n'êtes pas à l'aide de laprefix
argumentsplit
, et vous travaillez dans un répertoire qui n'a pas d'autres fichiers qui commencent parsplit
par défaut dexa*
format de sortie. Aussi, remplacer le '4' avec votre choix de scission de la ligne de taille.Cela permettra de diviser le grand csv en morceaux de 999 lignes, avec l'en-tête en haut de chaque
Basés sur Ole Tange de réponse.
(re Ole réponse: Vous ne pouvez pas utiliser la ligne de comptage avec pipepart)
C'est une version plus robuste de Denis Williamsons'script. Le script crée beaucoup de fichiers temporaires, et ce serait une honte si ils ont été laissés traîner si la course était incomplète. Donc, nous allons ajouter un signal de piégeage (voir http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html et puis http://tldp.org/LDP/abs/html/debugging.html) et de supprimer de nos fichiers temporaires; c'est une meilleure pratique de toute façon.
Remplacer le " 13 " avec ce code de retour que vous souhaitez. Oh, et vous devriez probablement utiliser des mktemp de toute façon (comme certains l'ont déjà suggéré), donc aller de l'avant et d'enlever tmp_file" de la rm dans le piège de la ligne. Voir le signal de la page de manuel pour plus de signaux à attraper.
Je ne suis jamais sûr de les règles de la copie des scripts directement à partir de sites d'autres personnes, mais Geekology a une belle script pour faire ce que vous voulez, avec quelques commentaires de confirmer qu'elle fonctionne. Assurez-vous de ne
tail
-n
+2
comme indiqué dans un commentaire à proximité du fond.J'ai aimé le awk version de marco, adoptés de cette simplifié one-liner où vous pouvez facilement spécifier le split fraction granulaire comme vous le souhaitez:
J'ai vraiment aimé Rob et Dennis versions, tellement que je voulais améliorer.
Voici ma version:
Différences:
awk
au lieu detail
en raison deawk
avoir de meilleures performanceshead | cat
ligne au lieu de deux lignesL'utilisation de GNU Parallèle:
Si vous avez besoin d'exécuter une commande sur chacune des pièces, puis GNU Parallèle peut aider à le faire, aussi:
Si vous voulez diviser en 2 parties par cœur de PROCESSEUR (par exemple, 24 cores = 48 de taille égale pièces):
Si vous voulez diviser en 10 MO blocs:
Ci-dessous est un 4 de revêtement qui peut être utilisé pour préserver les csv en-tête (à l'aide de : la tête, le split, find, grep, xargs, et sed)
Explication:
Inspiré par @Arkady commentaire sur un one-liner.
split
ne montre pas de nom de fichier, mais le--additional-suffix
option nous permet de facilement contrôler ce à quoi s'attendrerm $part
(n'assume pas de fichiers avec le même suffixe)MYFILE=mycsv.csv && for part in $(split -n4 --additional-suffix=foo $MYFILE; ls *foo); do cat <(head -n1 $MYFILE) $part > $MYFILE.$part; rm $part; done
Preuve:
et bien sûr
head -2 *foo
pour voir l'en-tête est ajouté.