Comando Linux para concatenar um arquivo para si mesmo n vezes

28

Eu peguei um livro de arquivos de texto simples do Project Gutenberg (cerca de 0,5 MB) que eu quero concatenar para si mesmo n times a fim de gerar um arquivo de texto grande que eu possa testar alguns algoritmos. Existe um comando do Linux que eu possa usar para conseguir isso? cat parece ideal, mas parece não ser muito legal ao concatenar um arquivo para si mesmo, além de não abordar diretamente a parte n times da questão.

    
por Bryce Thomas 22.09.2011 / 14:29

3 respostas

31

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

execute 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, há o comando 'repeat'.

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

    
por 22.09.2011 / 14:43
1

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

Assumindo que N é o número de concatenações automáticas que você deseja fazer e que seu arquivo é denominado 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 de file chamado file2 , total_repeats é o número de vezes que file precisaria ser adicionado a file2 para torná-lo o mesmo como se file fosse concatenado a si mesmo N vezes.

O MATH está aqui, mais ou menos: MATH (gist)

É o primeiro semestre da ciência da computação, mas já faz um tempo desde que eu fiz uma prova de indução, então eu não consigo superá-la ... (também esta classe de recursão é bem conhecida por ser 2^Loops , então existe essa também ....)

POSIX

Eu uso algumas coisas que não são positivas, mas elas não são essenciais. Para os 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 linecount.

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.

tee com MATH

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

Aqui tee está lendo file , mas permanentemente anexando a ele, então ele continuará lendo o arquivo até que head pare. E sabemos quando pará-lo por causa de MATH . O acréscimo vai além, então usei um arquivo temporário. Você pode cortar as linhas em excesso de file também.

eval , o senhor das trevas!

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

Isso apenas se expande para cat file file file ... e é avaliado. Você pode fazer isso sem o arquivo $tmp , também:

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

O segundo head "engana" cat colocando um intermediário entre ele e a operação de gravação. Você pode enganar cat com outro cat , mas isso tem um comportamento inconsistente. Tente isto:

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' '
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 "
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)
" else printf "\$(printf '%03o\t' $((firstbyte-1)) )" fi }
' | sed -e "s/.*/$(yes '
 yes() { while true; do echo "$1"; done; }
' | head -n $total_repeats | tr -d '\n')/g" | tr '
ln=$linecount
for i in $(seq 1 $N); do
    <file head -n $ln >> file;
    ln=$((ln*2))
done
' '\n' >> file

Força sed a ler o arquivo inteiro como uma linha, captura todo o arquivo e cola $total_repeats do número de vezes.

Isso falhará, é claro, se você tiver algum caractere nulo em seu arquivo. Escolha um que você sabe que não está lá.

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

Isso é tudo por agora rapazes, espero que essa resposta arbitrária não tenha incomodado ninguém. Eu testei todos eles muitas vezes, mas eu sou apenas um usuário de shell de dois anos, então tenha isso em mente, eu acho. Agora para dormir ...

rm $tmp

    
por 02.03.2017 / 00:32
1

Você certamente pode usar cat para isso:

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

Para receber $n de cópias, você pode usar yes piped em 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
    
por 02.03.2017 / 13:58