GNU/Linux >> Tutoriales Linux >  >> Linux

cómo crear archivos multitar para una carpeta enorme

Escribí este script bash para hacerlo. Básicamente forma una matriz que contiene los nombres de los archivos para ir a cada tar, luego comienza tar en paralelo en todos ellos Puede que no sea la forma más eficiente, pero hará el trabajo como usted quiere. Sin embargo, puedo esperar que consuma grandes cantidades de memoria.

Deberá ajustar las opciones al comienzo del script. También puede cambiar las opciones tar cvjf en la última línea (como eliminar la salida detallada v para rendimiento o cambio de compresión j a z , etc...).

Guión

#!/bin/bash

# User configuratoin
#===================
files=(*.log)           # Set the file pattern to be used, e.g. (*.txt) or (*)
num_files_per_tar=5 # Number of files per tar
num_procs=4         # Number of tar processes to start
tar_file_dir='/tmp' # Tar files dir
tar_file_name_prefix='tar' # prefix for tar file names
tar_file_name="$tar_file_dir/$tar_file_name_prefix"

# Main algorithm
#===============
num_tars=$((${#files[@]}/num_files_per_tar))  # the number of tar files to create
tar_files=()  # will hold the names of files for each tar

tar_start=0 # gets update where each tar starts
# Loop over the files adding their names to be tared
for i in `seq 0 $((num_tars-1))`
do
  tar_files[$i]="$tar_file_name$i.tar.bz2 ${files[@]:tar_start:num_files_per_tar}"
  tar_start=$((tar_start+num_files_per_tar))
done

# Start tar in parallel for each of the strings we just constructed
printf '%s\n' "${tar_files[@]}" | xargs -n$((num_files_per_tar+1)) -P$num_procs tar cjvf

Explicación

Primero, todos los nombres de archivo que coinciden con el patrón seleccionado se almacenan en la matriz files . A continuación, el bucle for divide este arreglo y forma cadenas a partir de los segmentos. El número de cortes es igual al número de tarballs deseados. Las cadenas resultantes se almacenan en la matriz tar_files . El ciclo for también agrega el nombre del tarball resultante al comienzo de cada cadena. Los elementos de tar_files tome la siguiente forma (suponiendo 5 archivos/tarball):

tar_files[0]="tar0.tar.bz2  file1 file2 file3 file4 file5"
tar_files[1]="tar1.tar.bz2  file6 file7 file8 file9 file10"
...

La última línea del script, xargs se utiliza para iniciar múltiples tar procesos (hasta el número máximo especificado) donde cada uno procesará un elemento de tar_files matriz en paralelo.

Prueba

Lista de archivos:

$ls

a      c      e      g      i      k      m      n      p      r      t
b      d      f      h      j      l      o      q      s

Tarballs generados:$ls /tmp/tar*tar0.tar.bz2 tar1.tar.bz2 tar2.tar.bz2 tar3.tar.bz2


Aquí hay otro guión. Puede elegir si desea exactamente un millón de archivos por segmento o exactamente 30 segmentos. He optado por el primero en este script, pero el split palabra clave permite cualquier elección.

#!/bin/bash
#
DIR="$1"        # The source of the millions of files
TARDEST="$2"    # Where the tarballs should be placed

# Create the million-file segments
rm -f /tmp/chunk.*
find "$DIR" -type f | split -l 1000000 - /tmp/chunk.

# Create corresponding tarballs
for CHUNK in $(cd /tmp && echo chunk.*)
do
    test -f "$CHUNK" || continue

    echo "Creating tarball for chunk '$CHUNK'" >&2
    tar cTf "/tmp/$CHUNK" "$TARDEST/$CHUNK.tar"
    rm -f "/tmp/$CHUNK"
done

Hay una serie de sutilezas que podrían aplicarse a este script. El uso de /tmp/chunk. ya que el prefijo de la lista de archivos probablemente debería insertarse en una declaración constante, y el código no debería asumir que puede eliminar cualquier cosa que coincida con /tmp/chunk.* , pero lo he dejado así como una prueba de concepto en lugar de una utilidad pulida. Si estuviera usando esto, usaría mktemp para crear un directorio temporal para almacenar las listas de archivos.


Este hace exactamente lo que se solicitó:

#!/bin/bash
ctr=0;
# Read 1M lines, strip newline chars, put the results into an array named "asdf"
while readarray -n 1000000 -t asdf; do
  ctr=$((${ctr}+1));
# "${asdf[@]}" expands each entry in the array such that any special characters in
# the filename won't cause problems
  tar czf /destination/path/asdf.${ctr}.tgz "${asdf[@]}";
# If you don't want compression, use this instead:
  #tar cf /destination/path/asdf.${ctr}.tar "${asdf[@]}";
# this is the canonical way to generate output
# for consumption by read/readarray in bash
done <(find /source/path -not -type d);

readarray (en bash) también se puede usar para ejecutar una función de devolución de llamada, por lo que podría reescribirse para parecerse a:

function something() {...}
find /source/path -not -type d \
  | readarray -n 1000000 -t -C something asdf

GNU parallel podría aprovecharse para hacer algo similar (no probado; no tengo parallel instalado donde estoy, así que lo estoy improvisando):

find /source/path -not -type d -print0 \
  | parallel -j4 -d '\0' -N1000000 tar czf '/destination/path/thing_backup.{#}.tgz'

Como eso no se ha probado, puede agregar el --dry-run arg para ver lo que realmente hará. Me gusta más este, pero no todo el mundo tiene parallel instalado. -j4 hace que use 4 trabajos a la vez, -d '\0' combinado con find de -print0 hace que ignore los caracteres especiales en el nombre del archivo (espacios en blanco, etc.). El resto debe explicarse por sí mismo.

Se podría hacer algo similar con parallel pero no me gusta porque genera nombres de archivos aleatorios:

find /source/path -not -type d -print0 \
  | parallel -j4 -d '\0' -N1000000 --tmpdir /destination/path --files tar cz

No [¿todavía?] conozco una forma de hacer que genere nombres de archivo secuenciales.

xargs también podría usarse, pero a diferencia de parallel no hay una forma sencilla de generar el nombre del archivo de salida, por lo que terminaría haciendo algo estúpido/incorrecto como este:

find /source/path -not -type d -print0 \
  | xargs -P 4 -0 -L 1000000 bash -euc 'tar czf $(mktemp --suffix=".tgz" /destination/path/backup_XXX) "[email protected]"'

El OP dijo que no querían usar split... Pensé que parecía extraño como cat se volverá a unir a ellos muy bien; esto produce un alquitrán y lo divide en fragmentos de 3 gb:

tar c /source/path | split -b $((3*1024*1024*1024)) - /destination/path/thing.tar.

... y esto los desata en el directorio actual:

cat $(\ls -1 /destination/path/thing.tar.* | sort) | tar x

Linux
  1. Cómo crear una imagen de Windows para OpenStack

  2. Cómo crear un pem para su SSL existente

  3. Ejemplos de Linux cpio:cómo crear y extraer archivos cpio (y archivos tar)

  4. ¿Cómo puedo crear un archivo en cada carpeta?

  5. ¿Cómo deshabilitar la creación de la carpeta .Trash-1000?

Cómo crear una copia de seguridad con el comando tar en Linux

Comando Tar en Linux (Crear y Extraer Archivos)

Cómo crear un archivo Tar Gz

Cómo descomprimir archivos tar bz2 xz gz en Linux

Cómo crear un archivo Tar gz

Cómo crear un controlador de dominio en Linux para AD