Comando de Linux para concatenar un archivo consigo mismo n veces

31

Tomé un libro de archivos de texto sin formato del Proyecto Gutenberg (alrededor de 0,5 MB) que quiero concatenar consigo mismo nveces para generar un archivo de texto grande en el que pueda comparar algunos algoritmos. ¿Hay algún comando de Linux que pueda usar para lograr esto? catSuena ideal, pero no parece jugar demasiado bien con la concatenación de un archivo sobre sí mismo, además no aborda directamente los ntiempos parte de la pregunta.

Bryce Thomas
fuente
2
utilizar algún tipo de bucle y anexar? así que repite foo.txt >> bar.txt y envuélvelo en algo que ejecute el comando tantas veces?
Journeyman Geek

Respuestas:

35

Dos partes para esto, para mí, primero, usar cat para generar el archivo de texto en la salida estándar, y usar append para agregarlo a otro archivo, por ejemplo foo.txt >> bar.txt agregará foo.txt a bar.txt

luego ejecútalo n veces con

for i in {1..n};do cat foo.txt >> bar.txt; done

reemplazando n en ese comando con su número

debería funcionar, donde n es tu número

Si usa csh, está el comando 'repetir'.

repito partes relacionadas de la respuesta se copian desde aquí , y lo probé en un sistema ubuntu 11.04 en el shell bash predeterminado.

Journeyman Geek
fuente
3
Dato curioso: esto realmente funciona sin reemplazar 'n', en cuyo caso ejecutará el cuerpo una vez para cada carácter entre ASCII '1' y ASCII 'n' (es decir, 62 veces). Pero {1..12}correrá correctamente el cuerpo 12 veces.
Arnout Engelen
1
Es posible que desee redirigir toda la canalización, en lugar de agregar en cada iteración:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight
2

Estoy aburrido, así que aquí hay algunos métodos más sobre cómo concatenar un archivo consigo mismo, principalmente con headuna muleta. Disculpe si me explico demasiado, solo me gusta decir cosas: P


Suponiendo que Nes el número de autoconcatenaciones que desea hacer y que su archivo tiene un nombre file.

Variables:

linecount=$(<file wc -l)

total_repeats=$(echo "2^$N - 1" | bc) # obtained through the power of MATH

total_lines=$((linecount*(total_repeats+1)))

tmp=$(mktemp --suffix .concat.self)

Dada una copia de filellamado file2, total_repeatses el número de veces fileque debería agregarse file2para que sea igual que si fileestuviera concatenado a sí mismo N.

Dicho MATH está aquí, más o menos: MATH (esencia)

Es material de informática del primer semestre, pero ha pasado un tiempo desde que hice una prueba de inducción, así que no puedo superarlo ... (también se sabe que esta clase de recursión es así que 2^Loopstambién existe ...)


POSIX

Utilizo algunas cosas que no son posix pero no son esenciales. Para mis propósitos:

 yes() { while true; do echo "$1"; done; }

Oh, solo usé eso. Oh bueno, la sección ya está aquí ...


Métodos


head con seguimiento de recuento de líneas.

ln=$linecount
for i in $(seq 1 $N); do
    <file head -n $ln >> file;
    ln=$((ln*2))
done

Sin archivo temporal, sin gato, ni siquiera demasiadas matemáticas, toda alegría.


teecon MATEMÁTICAS

<file tee -a file | head -n $total_lines > $tmp
cat $tmp > file

Aquí teeestá leyendo, filepero añadiéndole perpetuamente, por lo que seguirá leyendo el archivo repetidamente hasta que lo headdetenga. Y sabemos cuándo detenerlo debido a MATH . El anexo va por la borda, así que utilicé un archivo temporal. También podría recortar el exceso de líneas file.


eval, el señor de la oscuridad!

eval "cat $(yes file | head -n $((total_repeats+1)) | tr '\n' ' ')" > $tmp
cat $tmp > file

Esto solo se expande cat file file file ...y lo evalúa. También puedes hacerlo sin el $tmparchivo:

eval "cat $(yes file | head -n $total_repeats | tr '\n' ' ')" |
  head -n $((total_lines-linecount)) >> file

El segundo head"truco" catal poner a un intermediario entre este y la operación de escritura. También podrías engañar cata otro cat, pero eso tiene un comportamiento inconsistente. Prueba esto:

test_double_cat() {
    local Expected=0
    local Got=0
    local R=0
    local file="$(mktemp --suffix .double.cat)"
    for i in $(seq 1 100); do

        printf "" > $file
        echo "1" >> $file
        echo "2" >> $file
        echo "3" >> $file

        Expected=$((3*$(<file wc -l)))

        cat $file $file | cat >> $file

        Got=$(<file wc -l)

        [ "$Expected" = "$Got" ] && R="$((R+1))"
    done
    echo "Got it right $R/100"
    rm $file
}

sed:

<file tr '\n' '\0' |
    sed -e "s/.*/$(yes '\0' | head -n $total_repeats | tr -d '\n')/g" |
        tr '\0' '\n' >> file

Obliga seda leer todo el archivo como una línea, captura todo y luego lo pega $total_repeatsvarias veces.

Por supuesto, esto fallará si tiene caracteres nulos en su archivo. Elige uno que sabes que no está allí.

find_missing_char() {
  local file="${1:-/dev/stdin}"

  firstbyte="$(<$file fold -w1 | od -An -tuC | sort -un | head -n 1)"
  if [ ! "$firstbyte" = "0" ]; then
    echo "\0"
  else
    printf "\\$(printf '%03o\t' $((firstbyte-1)) )"
  fi
}

Eso es todo por ahora muchachos, espero que esta respuesta arbitraria no moleste a nadie. Los probé muchas veces, pero solo soy un usuario de shell de dos años, así que tenlo en cuenta, supongo. Ahora a dormir...

rm $tmp

phicr
fuente
2

Ciertamente puedes usar catpara esto:

$ cat /tmp/f
foo
$ cat /tmp/foo /tmp/f
foo
foo

Para obtener $ncopias, puede usar yescanalizado en head -n $n:

$ yes /tmp/f | head -n 10
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f
/tmp/f

Poner eso juntos da

yes /tmp/f | head -n $n | xargs cat >/tmp/output
Toby Speight
fuente