Jeśli nie masz nic przeciwko zmianie kolejności wierszy i masz jądra GNU (tj. W niewbudowanym systemie Linux lub Cygwin, niezbyt stare od czasu shuf
pojawienia się w wersji 6.0), shuf
funkcja „losowo” zmienia kolejność wierszy pliku losowo. Możesz więc przetasować plik i wysłać pierwsze m wierszy do jednego pliku, a resztę do innego.
Nie ma idealnego sposobu na wykonanie tej wysyłki. Nie możesz po prostu połączyć w łańcuch, head
a tail
ponieważ head
buforowałby do przodu. Możesz użyć split
, ale nie zyskujesz elastyczności w odniesieniu do nazw plików wyjściowych. Możesz awk
oczywiście użyć :
<input shuf | awk -v m=$m '{ if (NR <= m) {print >"output1"} else {print} }'
Możesz użyć sed
, co jest niejasne, ale być może szybsze w przypadku dużych plików.
<input shuf | sed -e "1,${m} w output1" -e "1,${m} d" >output2
Lub możesz użyć tee
do skopiowania danych, jeśli Twoja platforma ma /dev/fd
; to dobrze, jeśli m jest małe:
<input shuf | { tee /dev/fd/3 | head -n $m >output1; } 3>&1 | tail -n +$(($m+1)) >output2
Przenośnie, możesz użyć awk, aby wywołać każdą linię po kolei. Zauważ, że awk nie jest zbyt dobry w inicjowaniu generatora liczb losowych; losowość nie tylko zdecydowanie nie nadaje się do kryptografii, ale nawet nie jest bardzo dobra do symulacji numerycznych. Ziarno będzie takie samo dla wszystkich wywołań awk w dowolnym systemie z okresem jednej sekundy.
<input awk -v N=$(wc -l <input) -v m=3 '
BEGIN {srand()}
{
if (rand() * N < m) {--m; print >"output1"} else {print >"output2"}
--N;
}'
Jeśli potrzebujesz lepszej losowości, możesz zrobić to samo w Perlu, który porządnie zasiewa RNG.
<input perl -e '
open OUT1, ">", "output1" or die $!;
open OUT2, ">", "output2" or die $!;
my $N = `wc -l <input`;
my $m = $ARGV[0];
while (<STDIN>) {
if (rand($N) < $m) { --$m; print OUT1 $_; } else { print OUT2 $_; }
--$N;
}
close OUT1 or die $!;
close OUT2 or die $!;
' 42