Commande Linux pour concaténer un fichier à lui-même n fois

31

J'ai pris un livre de fichiers texte brut du projet Gutenberg (environ 0,5 Mo) que je veux concaténer à lui-même nfois afin de générer un fichier texte volumineux sur lequel je peux comparer certains algorithmes. Existe-t-il une commande Linux que je peux utiliser pour y parvenir? catsemble idéal, mais ne semble pas jouer trop bien avec la concaténation d'un fichier sur lui-même, en plus ne répond pas directement à la npartie fois de la question.

Bryce Thomas
la source
2
utiliser une sorte de boucle, et ajouter? alors répétez foo.txt >> bar.txt et enveloppez-le dans quelque chose qui exécutera la commande autant de fois?
Journeyman Geek

Réponses:

35

Pour moi, deux parties - d'abord - pour utiliser cat pour sortir le fichier texte en sortie standard, et utiliser append pour l'ajouter à un autre fichier - par exemple foo.txt >> bar.txt ajoutera foo.txt à bar.txt

puis exécutez-le n fois avec

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

remplacer n dans cette commande par votre numéro

devrait fonctionner, où n est votre numéro

Si vous utilisez csh, il y a la commande 'repeat'.

répéter les parties liées de la réponse sont copiées d'ici , et je l'ai testé sur un système ubuntu 11.04 sur le shell bash par défaut.

Compagnon Geek
la source
3
Fait amusant: cela fonctionne en fait sans remplacer 'n', auquel cas il exécute le corps une fois pour chaque caractère entre ASCII '1' et ASCII 'n' (donc 62 fois). Mais {1..12}exécutera correctement le corps 12 fois.
Arnout Engelen
1
Vous voudrez peut-être simplement rediriger l'ensemble du pipeline, plutôt que d'ajouter à chaque itération:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight
2

Je m'ennuie donc voici quelques méthodes supplémentaires pour concaténer un fichier à lui-même, principalement avec headune béquille. Pardonnez-moi si je me surexplique, j'aime juste dire des choses: P


En supposant que Nle nombre d'auto-concaténations que vous voulez faire et que votre fichier est nommé 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)

Étant donné une copie de fileappelé file2, total_repeatsc'est le nombre de fois filequ'il faudrait ajouter pour file2le rendre comme s'il fileétait concaténé à lui-même Nfois.

Dit MATH est ici, plus ou moins: MATH (gist)

C'est des trucs informatiques du premier semestre mais ça fait un moment que je n'ai pas fait de preuve d'induction donc je ne peux pas m'en remettre 2^Loops...


POSIX

J'utilise quelques éléments non posix mais ils ne sont pas essentiels. Pour mes fins:

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

Oh, je l'ai seulement utilisé. Eh bien, la section est déjà là ...


Les méthodes


head avec suivi linecount.

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

Pas de fichier temporaire, pas de chat, pas encore trop de maths, toute joie.


teeavec MATH

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

Voici la teelecture filemais en y ajoutant perpétuellement, donc il continuera à lire le fichier en boucle jusqu'à ce headqu'il s'arrête. Et nous savons quand l'arrêter à cause de MATH . L'ajout passe par dessus bord, j'ai donc utilisé un fichier temporaire. Vous pouvez également couper les lignes en excès file.


eval, le seigneur des ténèbres!

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

Cela se développe cat file file file ...et l'évale. Vous pouvez aussi le faire sans le $tmpfichier:

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

La seconde head"astuces" caten mettant un intermédiaire entre elle et l'opération d'écriture. Vous pouvez également tromper catavec un autre cat, mais cela a un comportement incohérent. Essaye ça:

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

Force la sedlecture de l'ensemble du fichier sous forme de ligne, capture l'intégralité de celui-ci, puis le colle $total_repeatsplusieurs fois.

Cela échouera bien sûr si vous avez des caractères nuls dans votre fichier. Choisissez celui dont vous savez qu'il n'est pas là.

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
}

C'est tout pour l'instant les gars, j'espère que cette réponse arbitraire n'a dérangé personne. Je les ai tous testés plusieurs fois, mais je ne suis qu'un utilisateur shell de deux ans, alors gardez cela à l'esprit, je suppose. Maintenant pour dormir ...

rm $tmp

phicr
la source
2

Vous pouvez certainement utiliser catpour cela:

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

Pour obtenir des $ncopies, vous pouvez utiliser des yescanalisations dans 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

Mettre cela ensemble donne

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