Je suis sur Ubuntu 16.04.
J'ai un dossier avec beaucoup de fichiers texte (presque 12k). Je dois tous les télécharger sur un site Web qui accepte .tar.gz
puis les décompresse automatiquement, mais avec une limite de 10 Mo (10000 Ko) par fichier (chaque fichier doit donc être décompressé seul). Si je tar.gz
tous ces fichiers, le fichier résultant est d'environ 72 Mo.
Ce que je voudrais faire est de créer huit fichiers .tar.gz
, chacun de taille/dimension (strictement) inférieure à 10000 Ko.
Alternativement, on peut supposer que tous les fichiers ci-dessus ont approximativement la même dimension. Je voudrais donc créer huit fichiers .tar.gz
avec plus ou moins la même quantité de fichiers.
Comment puis-je effectuer l'une de ces deux tâches?
Je vais parfaitement bien avec une solution qui implique une interface graphique, CLI ou des scripts. Je ne cherche pas la vitesse ici, j'ai juste besoin que ce soit fait.
Totalement un patchwork et une esquisse rapide et approximative, mais testé sur un répertoire de 3000 fichiers, le script ci-dessous effectue un travail extrêmement rapide:
#!/usr/bin/env python3
import subprocess
import os
import sys
splitinto = 2
dr = sys.argv[1]
os.chdir(dr)
files = os.listdir(dr)
n_files = len(files)
size = n_files // splitinto
def compress(tar, files):
command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
proc = subprocess.Popen(command, stdin=subprocess.PIPE)
with proc:
proc.stdin.write(b'\0'.join(map(str.encode, files)))
proc.stdin.write(b'\0')
if proc.returncode:
sys.exit(proc.returncode)
sub = []; tar = 1
for f in files:
sub.append(f)
if len(sub) == size:
compress(tar, sub)
sub = []; tar += 1
if sub:
# taking care of left
compress(tar, sub)
compress_split.py
Exécutez-le avec le répertoire avec vos fichiers comme argument:
python3 /path/tocompress_split.py /directory/with/files/tocompress
les fichiers numérotés .tar.gz
seront créés dans le même répertoire que celui où se trouvent les fichiers.
Le scénario:
Plus sophistiqué consiste à utiliser la taille maximale (en Mo) des morceaux en tant que (second) argument. Dans le script ci-dessous, les morceaux sont écrits dans un fichier compressé dès que le morceau atteint (passe) le seuil.
Étant donné que le script est déclenché par les morceaux, dépassant le seuil, cela ne fonctionnera que si la taille de (tous) les fichiers est considérablement plus petite que la taille du morceau.
#!/usr/bin/env python3
import subprocess
import os
import sys
dr = sys.argv[1]
chunksize = float(sys.argv[2])
os.chdir(dr)
files = os.listdir(dr)
n_files = len(files)
def compress(tar, files):
command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
proc = subprocess.Popen(command, stdin=subprocess.PIPE)
with proc:
proc.stdin.write(b'\0'.join(map(str.encode, files)))
proc.stdin.write(b'\0')
if proc.returncode:
sys.exit(proc.returncode)
sub = []; tar = 1; subsize = 0
for f in files:
sub.append(f)
subsize = subsize + (os.path.getsize(f)/1000000)
if subsize >= chunksize:
compress(tar, sub)
sub = []; tar += 1; subsize = 0
if sub:
# taking care of left
compress(tar, sub)
Courir:
python3 /path/tocompress_split.py /directory/with/files/tocompress chunksize
... où chunksize est la taille de entrée pour la commande tar.
Dans celui-ci, les améliorations suggérées par @DavidFoerster sont incluses. Merci beaucoup!
Une approche pure Shell:
files=(*);
num=$((${#files[@]}/8));
k=1
for ((i=0; i<${#files[@]}; i+=$num)); do
tar cvzf files$k.tgz -- "${files[@]:$i:$num}"
((k++))
done
files=(*)
: enregistre la liste des fichiers (y compris les répertoires, le cas échéant, passez à files=(*.txt)
pour n’obtenir que les éléments portant l’extension txt
) dans le tableau $files
.num=$((${#files[@]}/8));
: ${#files[@]}
est le nombre d'éléments dans le tableau $files
. La $(( ))
est la façon dont arithmétique de bash (limitée). Ainsi, cette commande définit $num
sur le nombre de fichiers divisé par 8.k=1
: juste un compteur pour nommer les archives.for ((i=0; i<${#files[@]}; i+=$num)); do
: parcourez les valeurs du tableau. $i
est initialisé à 0
(le premier élément du tableau) et incrémenté de $num
. Cela continue jusqu'à ce que nous ayons parcouru tous les éléments (fichiers).tar cvzf files$i.tgz -- ${files[@]:$i:$num}
: en bash, vous pouvez obtenir une tranche de tableau (partie d'un tableau) en utilisant ${array[@]:start:length}
, donc ${array[@]:2:3}
renverra trois éléments à partir du deuxième. Ici, nous prenons une tranche qui commence à la valeur actuelle de $i
et contient $num
long éléments. Le --
est nécessaire au cas où l'un de vos noms de fichier puisse commencer par un -
.((k++))
: incrémenter $k