Вместо того, чтобы смешать с системным уровнем Python, мог бы я предлагать использовать что-то как virtualenv
вместе с virtualenvwrapper
. Вместе эти 2 инструмента делают это довольно тривиальным для выдерживания собственных локальных копий библиотек Python + вместо того, чтобы иметь необходимость попытаться сохранить системную установку уровня Python в состоянии OK для системного программного обеспечения уровня, которое требует его.
virtualenv
virtualenv является инструментом для создания изолированных сред Python.
Это создает среду, которая имеет ее собственные каталоги установки, который не совместно использует библиотеки с другими virtualenv средами (и дополнительно не получает доступ к глобально установленным библиотекам ни один).
virtualenvwrapper
virtualenvwrapper является рядом расширений virtualenv инструмента Ian Bicking. Расширения включают обертки для создания и удаления виртуальных сред и в других отношениях руководящий Ваш рабочий процесс разработки, помогая работать над больше чем одним проектом за один раз, не представляя конфликты в их зависимостях.
Большинство языков обеспечивает эти типы инструментов теперь. См. мое сообщение по этому названному вопросу: Рекомендуемый дистрибутив Linux для статистики? для других языков также.
Похоже, вы просите решение проблемы упаковки в контейнеры . Насколько нам известно, не существует способа сделать это одновременно оптимально и быстро (но мы также не знаем, что его нет; это открытый вопрос).
Но вы можете приблизиться. Одна утилита для этого называется datapacker . Не использовал тот; нашел его поиском. Я уверен, что есть еще кое-что.
Лично я использую тот, который написал сам. (Обратите внимание, что все они выводят список файлов, которые попадают в каждую корзину; вы можете легко использовать cat
, чтобы собрать их в один текстовый файл.) Комментарий относится к bfpp
, который это еще одна программа, которую я написал, которая находит оптимальное решение, если у вас есть только несколько (например, менее 10) файлов:
#!/usr/bin/perl -w
#
# Sane bin packer. Attempts to finds a way to arrange a set of items
# into the fewest bins. Uses first-fit decreasing, which will get within
# 11⁄9⋅OPT + 6⁄9 (where OPT is the optimal number of discs, as found by
# bfpp). Unlike bfpp, this program will finish quickly.
#
# Also, this program features many more non-ASCII characters than bfpp.
# This is probably its most important feature.
use strict;
use 5.010;
use Data::Dump qw(pp);
use File::Next;
use List::Util qw(sum);
use String::ShellQuote qw(shell_quote);
use Carp qw(confess croak carp);
sub usage($) {
say STDERR "Usage: $0 bin-size-megabytes file1 file2 ...";
exit shift;
}
sub parse_command_line() {
usage(1) if @ARGV < 3;
usage(0) if $ARGV[0] =~ /^--?[h?]/;
my $size = shift @ARGV;
given ($size) {
when (/^dvd5?$/) {
$size = 4011;
}
when (/^dvd9$/) {
$size = 7291;
}
when (/^bd(-r)?1?$/) {
$size = 21360;
}
when (/^bd(-r)?2$/) {
$size = 42720;
}
when (/^\d+$/) {
# do nothing, already number
}
default {
say STDERR "ERROR: Size must be number or known size constant (dvd, dvd9, bd, bd2)";
usage(1);
}
}
return {
bin_size => $size * 1024 * 1024,
items => get_item_info(@ARGV),
};
}
sub get_item_info {
my %items;
my ($in_group, $group_no) = (0, 0);
foreach my $item (@_) {
if ('(' eq $item ) {
$in_group and confess "Nested groups not supported";
$in_group = 1;
++$group_no;
next;
} elsif (')' eq $item) {
$in_group or croak "Can't close a group when none open";
$in_group = 0;
next;
}
my $key;
$in_group and $key = "!!__GROUP${group_no}__!!";
if (-f $item) {
defined $key or ($key = $item) =~ s/\..{2,4}$//;
push @{$items{$key}{members}}, $item;
$items{$key}{size} += -s _;
} elsif (-d $item) {
$key //= $item;
my $files = File::Next::files($item);
while (defined(my $file = $files->())) {
push @{$items{$key}{members}}, $file;
$items{$key}{size} += -s $file;
}
} else {
confess "Not sure how to handle $item (weird type or doesn't exist)"
}
}
$in_group and carp "WARNING: Group wasn't closed";
return \%items;
}
sub check_sanity($) {
my $info = shift;
my $_;
my $binsize = $info->{bin_size};
my @dontfit = grep $info->{items}{$_}{size} > $binsize,
keys %{$info->{items}};
if (@dontfit) {
say "\nWARNING! WARNING! WARNING! WARNING!";
say "The following items are larger than the bin size:";
say pp(\@dontfit);
say "This is going to lead to some funny results.\n";
say "WARNING! WARNING! WARNING! WARNING!\n";
}
return $info;
}
sub approximate_best {
my $info = shift;
my @sorted
= sort { $info->{items}{$::b}{size} <=> $info->{items}{$::a}{size} }
keys %{$info->{items}};
my @bins;
FILE: foreach my $file (@sorted) {
my $size = $info->{items}{$file}{size};
BIN: foreach my $bin (@bins) {
next BIN unless $bin->{remaining} >= $size;
push @{$bin->{contents}}, $file;
$bin->{remaining} -= $size;
next FILE;
}
# didn't find a bin, open a new one
push @bins,
{
remaining => $info->{bin_size} - $size,
contents => [$file],
};
}
$info->{bins} = \@bins;
return $info;
}
sub print_bins($) {
my $info = shift;
my $_;
my $bins = $info->{bins};
#<<< [Hide this mess from PerlTidy]
use locale;
my @bins_full = map { # for each disk
[ sort( # sort each disk's fileset
map { # for each fileset
@{$info->{items}{$_}{members}}
} @{$_->{contents}}
) ];
} @$bins;
#>>>
for (my $d = 0; $d < @bins_full; ++$d) {
print <<DISC
DISC #@{[$d + 1]}: (@{[ int($bins->[$d]{remaining}/1024/1024) ]} MiB empty)
@{[ join(qq{\n }, @{$bins_full[$d]}) ]}
DISC
}
say "As space-separated, escaped values (for shell):";
for (my $d = 0; $d < @bins_full; ++$d) {
say $d+1, q{: }, shell_quote @{$bins_full[$d]};
}
return undef;
}
# believe it or not, the below is code.
print_bins approximate_best check_sanity parse_command_line;
First Fit Decreasing[1128860] strategy[1128395], вы можете использовать следующий скрипт Awk (красивый и понятный) с помощью [1128396]tac[1128397] для чтения входного файла снизу (это требуется только потому, что он отсортирован по размеру файла в порядке возрастания): Затем просто объедините его с [1128398]так[1128399] в [1128400]bash[1128401]:
Например, установив [1128402]Max_bin_size = 5 * 2^20[1128403] (5 Мб), вы увидите, что некоторое дополнительное пространство потребляется меньшими по размеру файлами, которые не расположены в последовательном порядке:
Proto Local Address Foreign Address State
TCP 10.0.0.2:56702 ARTEMIS:ms-wbt-server ESTABLISHED
TCP 127.0.0.1:19872 Athena:49172 ESTABLISHED
TCP 192.168.1.127:2869 192.168.1.254:49565 TIME_WAIT
TCP 192.168.1.127:56523 stackoverflow:http ESTABLISHED
Компромисс - это время обработки, однако, где-то между [1128404]O(N)[1128405] и [1128406]O(N[1128861]2[1128862])[1128407] в зависимости от распределения элементов, размеров элементов и размера бина. Это достаточно быстро для Вашего примера:
Да. Использование сценария bash:
#!/bin/bash
groupsize=0
groupcnt=0
cat unix_StackExchange_question.txt | while read fsize fname
do
[ "$groupsize" == "0" ] && echo "Group : GROUP_$groupcnt"
echo -en "\t $fname\n"
((groupsize+=$fsize))
#cp $fname GROUP_$groupcnt
if [ "$groupsize" -gt "5000000" ]
then
((groupcnt++))
groupsize=0
fi
done
awk -v sizelimit=5000000 -v outputfilename=shorter_list \
'BEGIN {target=outputfilename ".0000"}; '\
'{sum+=$1; '\
'if(sum>sizelimit) { file_index++; target=outputfilename "." sprintf("%04d",file_index); sum=$1;}; '\
'print $0 >target}' file
должен сделать то, что вы хотите. Тем не менее, вы должны изменить лимит размера. Я использовал меньшее значение для тестирования (что может быть полезно и для вашего тестирования).
Этот должен работать, но он медленный (1 мин. 18 сек. На 500 записей)
#!/bin/bash
#reformatting the initial file to remove tab
SRC=`cat file.txt | expand`
outputs_dir="outputs"
if [ ! -d "$outputs_dir" ];then
mkdir "$outputs_dir"
else
echo "$outputs_dir exist"
#rm "$outputs_dir"/*
fi
#init file outputs array with 2 files first one is in case files is bigger than 5GB
foutputs_array=( "$outputs_dir"/leftover.txt "$outputs_dir"/file1.txt )
#init file size array. Each time a file will be added to an output file, its size will be added here.
# If its size doesn't fit in an existing file, it will be added to a new file. New file will be added to foutputs_array,...
# If it doesn't fit anywhere, it will go to leftover.
fsize_array=( "0" "0" )
#5GB limit
FLIMIT=5242880
FLAG=0
i=1
array_index=1
fitIn(){
local file_size=$1
local total_size=$2
#echo "summing.." >&2
sum=$(expr $file_size + $total_size)
#echo "sum=" "$sum" >&2
if [[ "$sum" -le "$FLIMIT" ]];then
echo 0
else
echo 1
fi
}
while read fsize fname
do
# echo "array_index=" $array_index ${fsize_array[@]} "fsize"$fsize ${fsize_array[$array_index]}
check_size=`fitIn $fsize ${fsize_array[$array_index]}`
# echo "check_size" $check_size
if [ "$fsize" -le "$FLIMIT" -a "$check_size" -eq "0" ];then
# echo "In limit"
FLAG=0
elif [ $fsize -le $FLIMIT ];then
# echo "In max limit"
FLAG=0
while [ $check_size -eq "1" ]
do
# echo $array_index $i
(( array_index++ ))
(( i++ ))
if [ -z ${fsize_array[$array_index]} ];then
fsize_array[$array_index]=0
fi
check_size=`fitIn $fsize ${fsize_array[$array_index]}`
done
# echo "new position" $array_index
foutputs_array[$array_index]="$outputs_dir"/file${i}.txt
else
echo "$fsize $fname doesn't fit anywhere!"
FLAG=1
array_index=0
fi
if [ $FLAG -eq 0 ];then
(( fsize_array[$array_index]+=$fsize ))
fi
echo "$fsize" "$fname" >> "${foutputs_array[$array_index]}"
array_index=1
i=1
done <<< "$SRC"
На прекрасном, понятном Python:
#!/usr/bin/env python
with open('unix_StackExchange_question.txt') as f:
files = f.read()
files = files.split('\n')
group = list()
group_size = 0
n = 0
for f in files:
pair = f.split()
if not pair:
break
size = int(pair[0])
name = pair[1]
group_size += size
group.append(f)
# assume the files are in ascending order as per the op's question
if group_size + size >= 5000000:
n += 1
group_size = 0
print 'file %s:\n\t' % n +'\n\t'.join(x for x in group)
group = list()
Просто сохраните как 5GBfiles.py
и chmod + x 5GBfiles.py
и готово!
Это должно работать с bash
:
#!/bin/bash
accumulated_size=0
file_counter=0
out_file=file_0000
while read size name; do
if [ "$accumulated_size" -gt 5368709120 ]; then
(( file_counter += 1 ))
out_file=$(printf 'file_%04d' "$file_counter")
echo -n >"out_file"
accumulated_size=0
fi
echo "$size $name" >>"$out_file"
(( accumulated_size += size ))
done <unix_StackExchange_question.txt
Новый файл будет запускаться для первой строки, размер которой превышает 5GiB. Таким образом, каждый файл будет содержать размеры, суммарно превышающие 5GiB (если только последний файл не очень большой).
Это действительно должно быть сделано с помощью awk
скрипта - следующий эквивалент в awk
:
awk -v out_file=file_0000 '{
if(accumulated_size > 5368709120){
file_counter += 1
out_file=sprintf("file_%04d", file_counter)
accumulated_size=0
}
print >out_file
accumulated_size+=$1
}' unix_StackExchange_question.txt