Comando Linux per concatenare un file su se stesso n volte


31

Ho preso un semplice file di testo da Project Gutenberg (circa 0,5 MB) che voglio concatenare a se stesso nvolte per generare un grande file di testo su cui posso confrontare alcuni algoritmi. Esiste un comando Linux che posso usare per raggiungere questo obiettivo? catsembra ideale, ma non sembra giocare troppo bene concatenando un file su se stesso, inoltre non affronta direttamente i ntempi della domanda.


2
usare un qualche tipo di loop e aggiungere? quindi ripeti foo.txt >> bar.txt e avvolgilo in qualcosa che eseguirà il comando tante volte?
Journeyman Geek

Risposte:


35

In due parti, per me, per prima cosa, utilizzare cat per generare il file di testo nell'output standard e utilizzare append per aggiungerlo a un altro file, ad esempio foo.txt >> bar.txt aggiungerà foo.txt a bar.txt

quindi eseguirlo n volte con

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

sostituendo n in quel comando con il tuo numero

dovrebbe funzionare, dove n è il tuo numero

Se usi csh, c'è il comando 'ripeti'.

Ripetere parti correlate della risposta vengono copiate da qui e l'ho testato su un sistema Ubuntu 11.04 sulla shell bash predefinita.


3
Curiosità: in realtà funziona senza sostituire 'n', nel qual caso eseguirà il corpo una volta per ogni personaggio tra ASCII '1' e ASCII 'n' (quindi 62 volte). Ma {1..12}eseguirà correttamente il corpo 12 volte.
Arnout Engelen,

1
Potresti voler reindirizzare l'intera pipeline, piuttosto che aggiungere in ogni iterazione:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight

2

Sono annoiato, quindi ecco alcuni altri metodi su come concatenare un file a se stesso, principalmente con headuna stampella. Scusatemi se mi spiego troppo, mi piace solo dire cose: P


Supponendo Nè il numero di auto-concatenazioni che si desidera eseguire e che il file sia denominato file.

variabili:

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)

Data una copia di filechiamato file2, total_repeatsè il numero di volte fileche dovrebbe essere aggiunto file2per renderlo uguale a se filefosse concatenato a se stesso N.

Detto MATH è qui, più o meno: MATH (sintesi)

È roba di informatica del primo semestre ma è passato un po 'di tempo da quando ho fatto una prova di induzione quindi non riesco a superarla ... (anche questa classe di ricorsione è abbastanza conosciuta per esserci, 2^Loopsquindi c'è anche quella ....)


POSIX

Uso alcune cose non posix ma non sono essenziali. Per i miei scopi:

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

Oh, l'ho solo usato. Vabbè, la sezione è già qui ...


metodi


head con tracciamento linecount.

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

Nessun file temporaneo, nessun gatto, nemmeno troppa matematica, tutta gioia.


teecon MATH

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

Qui teesta leggendo filema accodando perpetuamente ad esso, quindi continuerà a leggere il file ripetuto fino a quando headnon lo interrompe. E sappiamo quando fermarlo a causa di MATH . L'aggiunta va in mare, quindi ho usato un file temporaneo. Potresti anche tagliare le linee in eccesso file.


eval, il signore delle tenebre!

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

Questo si espande cat file file file ...e lo eleva. Puoi farlo anche senza il $tmpfile:

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

Il secondo head"trucchi" catmettendo un intermediario tra esso e l'operazione di scrittura. Potresti ingannare anche catun altro catma questo ha un comportamento incoerente. Prova questo:

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

Forza la sedlettura dell'intero file come una riga, lo cattura tutto, quindi lo incolla il $total_repeatsnumero di volte.

Questo ovviamente fallirà se nel tuo file sono presenti caratteri null. Scegline uno che sai che non c'è.

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
}

Questo è tutto per ora ragazzi, spero che questa risposta arbitraria non abbia disturbato nessuno. Ho provato tutti loro molte volte, ma sono solo un utente della shell di due anni, quindi tienilo a mente, suppongo. Adesso a dormire ...

rm $tmp


2

Puoi certamente usare catper questo:

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

Per ottenere $ncopie, è possibile utilizzare il yespiping in 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

Metterlo insieme dà

yes /tmp/f | head -n $n | xargs cat >/tmp/output
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.