Comando Linux para concatenar um arquivo para si mesmo n vezes


31

Peguei um livro de arquivo de texto sem formatação do Project Gutenberg (em torno de 0,5 MB), que quero concatenar para si próprio nvezes, a fim de gerar um arquivo de texto grande no qual eu possa comparar alguns algoritmos. Existe um comando linux que eu possa usar para conseguir isso? catparece ideal, mas não parece muito bom concatenar um arquivo para si mesmo, além de não abordar diretamente os nmomentos que fazem parte da pergunta.


2
usar algum tipo de loop e anexar? então repita foo.txt >> bar.txt e envolva isso em algo que executará o comando tantas vezes?
Journeyman Geek

Respostas:


35

Duas partes para isso, para mim - primeiro - usar cat para enviar o arquivo de texto para a saída padrão e usar append para adicioná-lo a outro arquivo - por exemplo, foo.txt >> bar.txt anexará foo.txt a bar.txt

em seguida, execute-o n vezes com

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

substituindo n nesse comando pelo seu número

deve funcionar, onde n é o seu número

Se você usa csh, existe o comando 'repeat'.

repetir partes relacionadas da resposta são copiadas daqui e eu testei em um sistema ubuntu 11.04 no shell bash padrão.


3
Curiosidade: isso realmente funciona sem substituir 'n'; nesse caso, ele executará o corpo uma vez para cada caractere entre ASCII '1' e ASCII 'n' (62 vezes). Mas {1..12}irá executar o corpo corretamente 12 vezes.
Arnout Engelen 25/03

11
Você pode apenas redirecionar o pipeline inteiro, em vez de anexar em cada iteração:for i in {1..n};do cat foo.txt; done > bar.txt
Toby Speight

2

Estou entediado, então aqui estão mais alguns métodos sobre como concatenar um arquivo para si mesmo, principalmente com headuma muleta. Perdoe-me se eu me explicar demais, eu apenas gosto de dizer coisas: P


Supondo que Nseja o número de concatenações automáticas que você deseja fazer e que seu arquivo seja nomeado file.

Variáveis:

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 uma cópia do filechamado file2, total_repeatsé o número de vezes que fileseria necessário adicionar file2para torná-lo o mesmo que se filefosse concatenado para si próprio Nvezes.

Disse MATH está aqui, mais ou menos: MATH (essência)

É o primeiro semestre de ciência da computação, mas já faz um tempo desde que eu fiz uma prova de indução, para que eu não possa superar isso ... (também essa classe de recursão é bem conhecida por existir, 2^Loopstambém existe ...)


POSIX

Eu uso algumas coisas não-posix, mas elas não são essenciais. Para meus propósitos:

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

Ah, eu só usei isso. Oh bem, a seção já está aqui ...


Métodos


head com rastreamento de contagem de linha.

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

Nenhum arquivo temporário, nenhum gato, nem mesmo muita matemática, toda alegria.


teecom MATEMÁTICA

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

Aqui teeestá a leitura, filemas sempre anexada a ele, para que continue lendo o arquivo repetidamente até headparar. E sabemos quando parar por causa da MATEMÁTICA . O anexo é exagerado, então usei um arquivo temporário. Você também pode cortar o excesso de linhas file.


eval, o senhor das trevas!

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

Isso apenas se expande cat file file file ...e avalia. Você pode fazer isso sem o $tmparquivo também:

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

O segundo head"truques" cat, colocando um intermediário entre ele e a operação de gravação. Você também pode enganar catcom outro cat, mas isso tem um comportamento inconsistente. Tente o seguinte:

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

Força seda leitura do arquivo inteiro como uma linha, captura tudo e cola-o $total_repeatsvárias vezes.

Obviamente, isso falhará se você tiver caracteres nulos no seu arquivo. Escolha uma que você sabe que não está 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
}

Por enquanto é isso pessoal, espero que essa resposta arbitrária não incomode ninguém. Eu testei todos eles várias vezes, mas sou apenas um usuário de shell de dois anos, então lembre-se disso. Agora para dormir ...

rm $tmp


2

Você certamente pode usar catpara isso:

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

Para obter $ncópias, você pode usar o yescanal 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

Juntar isso dá

yes /tmp/f | head -n $n | xargs cat >/tmp/output
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.