Diviser: comment diviser en différents pourcentages?

14

Comment puis-je diviser un fichier texte en 70% et 30% en utilisant la commande split?

anévrisme
la source
Êtes-vous prêt à utiliser la commande split? Sinon, vous pouvez facilement le faire avec une manipulation de texte directe, certainement en utilisant perl ou python. Tant que le fichier n'est pas trop faux, lisez-le en mémoire sous forme de chaîne, puis divisez la chaîne. Si le fichier est trop volumineux, un travail supplémentaire est nécessaire.
Faheem Mitha
@Faheem Mitha Le fichier est de 64 Mo. J'aime l'idée d'utiliser split car c'est plus rapide que d'écrire du code. Je me demandais maintenant si je spécifie le nombre de lignes correspondant à 70% du fichier, j'obtiens un gros fichier et un petit fichier. Ça ne devrait pas marcher?
aneuryzm
Et oui .. cela a fonctionné .. Dois-je supprimer la question?
aneuryzm
À vous, mais pas nécessaire.
Faheem Mitha
Veuillez partager votre réponse. ( meta.stackexchange.com/questions/12513/… )
dogbane

Réponses:

13

Les commandes ci-dessous fonctionneront pour des pourcentages supérieurs à 50% (si vous souhaitez diviser uniquement en deux fichiers), approche rapide et sale.

1) répartir 70% sur la base des lignes

split -l $[ $(wc -l filename|cut -d" " -f1) * 70 / 100 ] filename 

2) répartir 70% sur la base des octets

split -b $[ $(wc -c filename|cut -d" " -f1) * 70 / 100 ] filename
forcefsck
la source
1
Sur MacOSX, wc renvoie parfois le nombre de lignes avec un espace devant, quelque chose qui rompt ce script. La première tuyauterie vers xargs supprimera ces espaces et fera fonctionner à nouveau: split -l $[ $(wc -l filename | xargs | cut -d" " -f1) * 70 / 100 ] filename
Emil Stenström
4

Vous pouvez utiliser csplitpour diviser en deux morceaux (en utilisant n'importe quel pourcentage), par exemple le premier morceau - les premiers 20% des lignes, le deuxième morceau - les 80% restants des lignes:

csplit infile $(( $(wc -l < infile) * 2 / 10 + 1))

$(wc -l < infile): nombre total de lignes
2 / 10: pourcentage
+1: ajoutez une ligne car elle csplitse diviseup to but not including line N

Cependant, vous ne pouvez fractionner que sur la base des lignes.
Fondamentalement, tant que vous avez le numéro de ligne via, $(( $(wc -l < file) * 2 / 10))vous pouvez utiliser n'importe quel outil orienté ligne:

sed 1,$(( $(wc -l < infile) * 2 / 10))'{
w 20-infile
d
}' infile > 80-infile

ou encore plus cool:

{ head -n$(( $(wc -l < infile) * 2 / 10)) > 20-infile; cat > 80-infile; } <infile

bien que certains headsoient stupides et ne soient pas conformes aux normes , cela ne fonctionnera pas sur toutes les configurations ...

don_crissti
la source
2
{   BS=$(($(wc -c <file) * $P / 100))
    dd count=1 bs="$BS" >file1; cat
} <file >file2 2>/dev/null

... devrait fonctionner pour ce cas simple, car vous ne vous séparez qu'une fois - et c'est probablement splitun peu exagéré. Tant que le fichier est adressable, ddne fera que faire une seule read()sur <stdin, et ainsi catest laissé pour commencer son read()quel que soit le point de la ddlaisse.

Si le fichier est volumineux, alors un count=1 bs=$big_ol_numpourrait devenir un peu difficile à manier, et il peut être bloqué avec quelques calculs de shell supplémentaires - mais simples -.

Une entrée non seekable - comme d'un tuyau - Peut fausser dd« les résultats, bien que cela puisse être manipulé aussi bien w / GNU dds » iflag=fullblock.

mikeserv
la source
0

Le code suivant utilise headet tailfonctionne avec n'importe quel rapport (40 à 60 dans ce cas):

export FILE_NAME=train.vw
head -n $[ $(wc -l ${FILE_NAME}|cut -d" " -f1) * 40 / 100 ] ${FILE_NAME} > train_40.vw
tail -n +$[ ($(wc -l ${FILE_NAME}|cut -d" " -f1) * 40 / 100) + 1 ] ${FILE_NAME} > train_60.vw
Alexandr Nikitin
la source