Podział: jak podzielić na różne wartości procentowe?

14

Jak mogę podzielić plik tekstowy na 70% i 30% za pomocą polecenia split?

aneuryzm
źródło
Czy lubisz korzystać z polecenia podziału? Jeśli nie, możesz to łatwo zrobić za pomocą prostej manipulacji tekstem, z pewnością używając Perla lub Pythona. Tak długo, jak plik nie jest zbyt zły, wczytaj go do pamięci jako ciąg, a następnie podziel ciąg. Jeśli plik jest zbyt duży, potrzeba więcej pracy.
Faheem Mitha
@Faheem Mitha Plik ma 64 MB. Podoba mi się pomysł używania podziału, ponieważ jest on szybszy niż pisanie kodu. Zastanawiałem się teraz, czy jeśli podam liczbę wierszy odpowiadających 70% pliku, otrzymam duży plik i mały plik. Czy to nie powinno działać?
aneuryzm
I tak .. zadziałało .. Czy powinienem usunąć pytanie?
aneuryzm
Do ciebie, ale nie konieczne.
Faheem Mitha
Proszę podzielić się swoją odpowiedzią. ( Meta.stackexchange.com/questions/12513/... )
dogbane

Odpowiedzi:

13

Poniższe polecenia będą działać dla wartości procentowych powyżej 50% (jeśli chcesz podzielić tylko na dwa pliki), szybkie i brudne podejście.

1) podział 70% na podstawie linii

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

2) podziel 70% na podstawie bajtów

split -b $[ $(wc -c filename|cut -d" " -f1) * 70 / 100 ] filename
forcefsck
źródło
1
Na MacOSX wc czasami zwraca liczbę wierszy ze spacją przed nimi, co psuje ten skrypt. Pierwsze potokowanie do xargs usunie te spacje i sprawi, że wszystko znowu split -l $[ $(wc -l filename | xargs | cut -d" " -f1) * 70 / 100 ] filename
zacznie
4

Możesz użyć csplitdo podzielenia na dwie części (używając dowolnego procentu) np. Pierwsza część - pierwsze 20% linii, druga część - pozostałe 80% linii:

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

$(wc -l < infile): całkowita liczba linii
2 / 10: procent
+1: dodaj jedną linię, ponieważ csplitdzieliup to but not including line N

Możesz jednak dzielić tylko na podstawie linii.
Zasadniczo, o ile masz numer linii $(( $(wc -l < file) * 2 / 10)), możesz użyć dowolnego narzędzia zorientowanego na linię:

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

lub nawet chłodniejsze:

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

chociaż niektóre headsą głupie i nie są zgodne ze standardami, więc nie będzie działać na wszystkich konfiguracjach ...

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

... powinien działać w tym prostym przypadku, ponieważ dzielisz tylko raz - i prawdopodobnie splitjest to trochę przesada. Tak długo, jak plik jest widoczny, ddwykona tylko jeden read()na nim <stdin, a więc catpozostanie rozpocząć read()od momentu, w którym ddgo opuści.

Jeśli plik jest duży, to count=1 bs=$big_ol_nummoże stać się trochę nieporęczny i można go zablokować za pomocą dodatkowej - ale prostej - matematyki powłoki.

Wejście niż możliwy do przeszukania - jak z rury - może pochylać dd"S wyniki, chociaż mogą być również traktowane jako w / GNU ddjest iflag=fullblock.

mikeserv
źródło
0

Poniższy kod używa headi taildziała z dowolnym współczynnikiem (w tym przypadku 40 do 60):

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
źródło