Split: ¿cómo dividir en diferentes porcentajes?

14

¿Cómo puedo dividir un archivo de texto en 70% y 30% usando el comando dividir?

aneuryzm
fuente
¿Estás casado con el uso del comando dividir? Si no, puede hacerlo fácilmente con la manipulación de texto directo, sin duda utilizando perl o python. Mientras el archivo no esté demasiado mal, léalo en la memoria como una cadena, luego divida la cadena. Si el archivo es demasiado grande, se necesita más trabajo.
Faheem Mitha
@Faheem Mitha El archivo tiene 64 MB. Me gusta la idea de usar split porque es más rápido que escribir código. Ahora me pregunto si especifico el número de líneas que corresponden al 70% del archivo, obtengo un archivo grande y un archivo pequeño. ¿No debería funcionar?
aneuryzm
Y sí ... funcionó ... ¿Debo eliminar la pregunta?
aneuryzm
Depende de usted, pero no es necesario.
Faheem Mitha
Por favor comparte tu respuesta. ( meta.stackexchange.com/questions/12513/… )
dogbane

Respuestas:

13

Los comandos a continuación funcionarán para porcentajes superiores al 50% (si desea dividir solo en dos archivos), enfoque rápido y sucio.

1) dividir 70% basado en líneas

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

2) dividir 70% basado en bytes

split -b $[ $(wc -c filename|cut -d" " -f1) * 70 / 100 ] filename
forcefsck
fuente
1
En MacOSX, wc a veces devuelve el número de líneas con un espacio delante, algo que rompe este script. La primera conexión a xargs eliminará esos espacios y hará que las cosas funcionen nuevamente: split -l $[ $(wc -l filename | xargs | cut -d" " -f1) * 70 / 100 ] filename
Emil Stenström
4

Puede usar csplitpara dividir en dos partes (usando cualquier porcentaje), por ejemplo, la primera pieza - primer 20% de líneas, segunda pieza - el 80% restante de líneas:

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

$(wc -l < infile): número total de líneas
2 / 10: porcentaje
+1: agrega una línea porque se csplitdivideup to but not including line N

Sin embargo, solo se puede dividir según las líneas.
Básicamente, siempre que tenga el número de línea a través $(( $(wc -l < file) * 2 / 10)), puede usar cualquier herramienta orientada a la línea:

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

o, incluso más fresco:

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

aunque algunos heads son tontos y no cumplen con los estándares, por lo que esto no funcionará en todas las configuraciones ...

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

... debería funcionar para este caso simple porque solo se está dividiendo una vez, por lo que probablemente splitsea ​​un poco exagerado. En tanto que el archivo es reubicable, ddsólo se va a hacer un solo read()sobre <stdin, y así catse deja a iniciar su read()en cualquier punto ddde salir.

Si el archivo es grande, a count=1 bs=$big_ol_numpodría ser un poco difícil de manejar, y puede bloquearse con algunas matemáticas de shell adicionales, pero simples.

Una entrada no seekable - como de un tubo - podrían sesgar dd'Resultados s, aunque esto puede ser manejado como bien w / GNU dd' s iflag=fullblock.

mikeserv
fuente
0

El siguiente código usa heady tailfunciona con cualquier relación (40 a 60 en este caso):

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
fuente